am 07f3bee2: Push Tag/NdefTag implementation details into the service.

Merge commit '07f3bee2db8b6e93ebbf7222676bd9f468e85569' into gingerbread-plus-aosp

* commit '07f3bee2db8b6e93ebbf7222676bd9f468e85569':
  Push Tag/NdefTag implementation details into the service.
diff --git a/api/current.xml b/api/current.xml
index c91c2b5..00a388b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -19598,6 +19598,18 @@
 <parameter name="context" type="android.content.Context">
 </parameter>
 </constructor>
+<constructor name="AlertDialog.Builder"
+ type="android.app.AlertDialog.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="theme" type="int">
+</parameter>
+</constructor>
 <method name="create"
  return="android.app.AlertDialog"
  abstract="false"
@@ -54177,6 +54189,42 @@
 <parameter name="table" type="java.lang.String">
 </parameter>
 </method>
+<method name="queryNumEntries"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+<parameter name="table" type="java.lang.String">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+</method>
+<method name="queryNumEntries"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+<parameter name="table" type="java.lang.String">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+</method>
 <method name="readExceptionFromParcel"
  return="void"
  abstract="false"
@@ -57049,6 +57097,2020 @@
 </method>
 </interface>
 </package>
+<package name="android.drm"
+>
+<class name="DrmConvertedStatus"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmConvertedStatus"
+ type="android.drm.DrmConvertedStatus"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="_statusCode" type="int">
+</parameter>
+<parameter name="_convertedData" type="byte[]">
+</parameter>
+<parameter name="_offset" type="int">
+</parameter>
+</constructor>
+<field name="STATUS_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_INPUTDATA_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_OK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="convertedData"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="offset"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="statusCode"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmErrorEvent"
+ extends="android.drm.DrmEvent"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmErrorEvent"
+ type="android.drm.DrmErrorEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<field name="TYPE_DRM_INFO_ACQUISITION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2012"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_FINALIZE_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2010"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_INITIALIZE_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_NOT_SUPPORTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2003"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_NO_INTERNET_CONNECTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2005"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_OUT_OF_MEMORY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2004"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REGISTRATION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2006"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REMOVE_ALL_RIGHTS_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2011"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_ACQUISITION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2008"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_NOT_INSTALLED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2001"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_RENEWAL_NOT_ALLOWED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2002"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_UNREGISTRATION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2007"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmEvent"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmEvent"
+ type="android.drm.DrmEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="getMessage"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUniqueId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="DRM_INFO_OBJECT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;drm_info_object&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DRM_INFO_STATUS_OBJECT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;drm_info_status_object&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_ALL_RIGHTS_REMOVED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1006"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_DRM_INFO_ACQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1007"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_FINALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1001"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_INITIALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1003"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REGISTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1002"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_ACQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1005"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_UNREGISTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1004"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmInfo"
+ type="android.drm.DrmInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="infoType" type="int">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="DrmInfo"
+ type="android.drm.DrmInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="infoType" type="int">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="get"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
+<method name="getData"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInfoType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="iterator"
+ return="java.util.Iterator&lt;java.lang.Object&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="keyIterator"
+ return="java.util.Iterator&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="put"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.Object">
+</parameter>
+</method>
+</class>
+<class name="DrmInfoEvent"
+ extends="android.drm.DrmEvent"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmInfoEvent"
+ type="android.drm.DrmInfoEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<field name="TYPE_ACCOUNT_ALREADY_REGISTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REMOVE_RIGHTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_INSTALLED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_WAIT_FOR_RIGHTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmInfoRequest"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmInfoRequest"
+ type="android.drm.DrmInfoRequest"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="infoType" type="int">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="get"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
+<method name="getInfoType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="iterator"
+ return="java.util.Iterator&lt;java.lang.Object&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="keyIterator"
+ return="java.util.Iterator&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="put"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.Object">
+</parameter>
+</method>
+<field name="ACCOUNT_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;account_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SUBSCRIPTION_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;subscription_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REGISTRATION_INFO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_ACQUISITION_INFO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_UNREGISTRATION_INFO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmInfoStatus"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmInfoStatus"
+ type="android.drm.DrmInfoStatus"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="_statusCode" type="int">
+</parameter>
+<parameter name="_data" type="android.drm.ProcessedData">
+</parameter>
+<parameter name="_mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<field name="STATUS_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_OK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="data"
+ type="android.drm.ProcessedData"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mimeType"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="statusCode"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmManagerClient"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmManagerClient"
+ type="android.drm.DrmManagerClient"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="acquireDrmInfo"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="drmInfoRequest" type="android.drm.DrmInfoRequest">
+</parameter>
+</method>
+<method name="canHandle"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="canHandle"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="checkRightsStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="checkRightsStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="checkRightsStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+</method>
+<method name="checkRightsStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+</method>
+<method name="closeConvertSession"
+ return="android.drm.DrmConvertedStatus"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="convertId" type="int">
+</parameter>
+</method>
+<method name="convertData"
+ return="android.drm.DrmConvertedStatus"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="convertId" type="int">
+</parameter>
+<parameter name="inputData" type="byte[]">
+</parameter>
+</method>
+<method name="getAvailableDrmEngines"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getConstraints"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+</method>
+<method name="getConstraints"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+</method>
+<method name="getDrmObjectType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="getDrmObjectType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="getOriginalMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="getOriginalMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="loadPlugIns"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="openConvertSession"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="processDrmInfo"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="drmInfo" type="android.drm.DrmInfo">
+</parameter>
+</method>
+<method name="removeAllRights"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeRights"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="removeRights"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="saveRights"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="drmRights" type="android.drm.DrmRights">
+</parameter>
+<parameter name="rightsPath" type="java.lang.String">
+</parameter>
+<parameter name="contentPath" type="java.lang.String">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setOnErrorListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorListener" type="android.drm.DrmManagerClient.OnErrorListener">
+</parameter>
+</method>
+<method name="setOnEventListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="eventListener" type="android.drm.DrmManagerClient.OnEventListener">
+</parameter>
+</method>
+<method name="setOnInfoListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="infoListener" type="android.drm.DrmManagerClient.OnInfoListener">
+</parameter>
+</method>
+<method name="unloadPlugIns"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="ERROR_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="DrmManagerClient.OnErrorListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onError"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="client" type="android.drm.DrmManagerClient">
+</parameter>
+<parameter name="event" type="android.drm.DrmErrorEvent">
+</parameter>
+</method>
+</interface>
+<interface name="DrmManagerClient.OnEventListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onEvent"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="client" type="android.drm.DrmManagerClient">
+</parameter>
+<parameter name="event" type="android.drm.DrmEvent">
+</parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
+</method>
+</interface>
+<interface name="DrmManagerClient.OnInfoListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onInfo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="client" type="android.drm.DrmManagerClient">
+</parameter>
+<parameter name="event" type="android.drm.DrmInfoEvent">
+</parameter>
+</method>
+</interface>
+<class name="DrmRights"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmRights"
+ type="android.drm.DrmRights"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rightsFilePath" type="java.lang.String">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="DrmRights"
+ type="android.drm.DrmRights"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rightsFilePath" type="java.lang.String">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+<parameter name="accountId" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="DrmRights"
+ type="android.drm.DrmRights"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rightsFilePath" type="java.lang.String">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+<parameter name="accountId" type="java.lang.String">
+</parameter>
+<parameter name="subscriptionId" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="DrmRights"
+ type="android.drm.DrmRights"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rightsFile" type="java.io.File">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="DrmRights"
+ type="android.drm.DrmRights"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="android.drm.ProcessedData">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="getAccountId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getData"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubscriptionId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DrmStore"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmStore"
+ type="android.drm.DrmStore"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<class name="DrmStore.Action"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmStore.Action"
+ type="android.drm.DrmStore.Action"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXECUTE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OUTPUT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PLAY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PREVIEW"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RINGTONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSFER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="DrmStore.ConstraintsColumns"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="EXTENDED_METADATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;extended_metadata&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LICENSE_AVAILABLE_TIME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;license_available_time&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LICENSE_EXPIRY_TIME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;license_expiry_time&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LICENSE_START_TIME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;license_start_time&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MAX_REPEAT_COUNT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;max_repeat_count&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="REMAINING_REPEAT_COUNT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;remaining_repeat_count&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
+<class name="DrmStore.DrmObjectType"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmStore.DrmObjectType"
+ type="android.drm.DrmStore.DrmObjectType"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="CONTENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RIGHTS_OBJECT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRIGGER_OBJECT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmStore.Playback"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmStore.Playback"
+ type="android.drm.DrmStore.Playback"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="PAUSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESUME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STOP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmStore.RightsStatus"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmStore.RightsStatus"
+ type="android.drm.DrmStore.RightsStatus"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="RIGHTS_EXPIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RIGHTS_INVALID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RIGHTS_NOT_ACQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RIGHTS_VALID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DrmSupportInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmSupportInfo"
+ type="android.drm.DrmSupportInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addFileSuffix"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fileSuffix" type="java.lang.String">
+</parameter>
+</method>
+<method name="addMimeType"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="getDescriprition"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFileSuffixIterator"
+ return="java.util.Iterator&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMimeTypeIterator"
+ return="java.util.Iterator&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setDescription"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="description" type="java.lang.String">
+</parameter>
+</method>
+</class>
+<class name="DrmUtils"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmUtils"
+ type="android.drm.DrmUtils"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getExtendedMetadataParser"
+ return="android.drm.DrmUtils.ExtendedMetadataParser"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="extendedMetadata" type="byte[]">
+</parameter>
+</method>
+</class>
+<class name="DrmUtils.ExtendedMetadataParser"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="get"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
+<method name="iterator"
+ return="java.util.Iterator&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="keyIterator"
+ return="java.util.Iterator&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="ProcessedData"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getAccountId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getData"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubscriptionId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
 <package name="android.gesture"
 >
 <class name="Gesture"
@@ -119919,6 +121981,17 @@
  visibility="public"
 >
 </constructor>
+<field name="BATTERY_HEALTH_COLD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BATTERY_HEALTH_DEAD"
  type="int"
  transient="false"
@@ -208598,6 +210671,32 @@
 <parameter name="object" type="T">
 </parameter>
 </method>
+<method name="addAll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="collection" type="java.util.Collection&lt;? extends T&gt;">
+</parameter>
+</method>
+<method name="addAll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="items" type="T...">
+</parameter>
+</method>
 <method name="clear"
  return="void"
  abstract="false"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 7a7f8ed..9fe1fb8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -49,6 +49,9 @@
 
 #include "BootAnimation.h"
 
+#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
+#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
+
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -244,12 +247,12 @@
     mFlingerSurfaceControl = control;
     mFlingerSurface = s;
 
-    mAndroidAnimation = false;
-    status_t err = mZip.open("/data/local/bootanimation.zip");
-    if (err != NO_ERROR) {
-        err = mZip.open("/system/media/bootanimation.zip");
-        if (err != NO_ERROR) {
-            mAndroidAnimation = true;
+    mAndroidAnimation = true;
+    if ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) ||
+        (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0)) {
+        if ((mZip.open(USER_BOOTANIMATION_FILE) != NO_ERROR) ||
+            (mZip.open(SYSTEM_BOOTANIMATION_FILE) != NO_ERROR)) {
+            mAndroidAnimation = false;
         }
     }
 
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index a5a1f01..14536bd 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -34,6 +34,8 @@
     { AID_MEDIA, "media.player" },
     { AID_MEDIA, "media.camera" },
     { AID_MEDIA, "media.audio_policy" },
+    { AID_DRMIO, "drm.drmIOService" },
+    { AID_DRM,   "drm.drmManager" },
     { AID_NFC,   "nfc" },
     { AID_RADIO, "radio.phone" },
     { AID_RADIO, "radio.sms" },
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 2714de5..61a8fc3 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -265,12 +265,22 @@
     
     public static class Builder {
         private final AlertController.AlertParams P;
+        private int mTheme;
         
         /**
          * Constructor using a context for this builder and the {@link AlertDialog} it creates.
          */
         public Builder(Context context) {
+            this(context, com.android.internal.R.style.Theme_Dialog_Alert);
+        }
+
+        /**
+         * Constructor using a context and theme for this builder and
+         * the {@link AlertDialog} it creates.
+         */
+        public Builder(Context context, int theme) {
             P = new AlertController.AlertParams(context);
+            mTheme = theme;
         }
         
         /**
@@ -783,7 +793,7 @@
          * to do and want this to be created and displayed.
          */
         public AlertDialog create() {
-            final AlertDialog dialog = new AlertDialog(P.mContext);
+            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
             P.apply(dialog.mAlert);
             dialog.setCancelable(P.mCancelable);
             dialog.setOnCancelListener(P.mOnCancelListener);
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 8f940d5..2382596 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -188,7 +188,7 @@
     /**
      * Return activity in receiverPackage that handles ACTION_APP_ERROR.
      *
-     * @param pm PackageManager isntance
+     * @param pm PackageManager instance
      * @param errorPackage package which caused the error
      * @param receiverPackage candidate package to receive the error
      * @return activity component within receiverPackage which handles
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2dd5819..69833032 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -53,7 +53,6 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.PackageParser.Package;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -85,11 +84,9 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.StatFs;
 import android.os.Vibrator;
 import android.os.FileUtils.FileStatus;
 import android.os.storage.StorageManager;
-import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.ClipboardManager;
 import android.util.AndroidRuntimeException;
@@ -262,18 +259,18 @@
     public Looper getMainLooper() {
         return mMainThread.getLooper();
     }
-    
+
     @Override
     public Context getApplicationContext() {
         return (mPackageInfo != null) ?
                 mPackageInfo.getApplication() : mMainThread.getApplication();
     }
-    
+
     @Override
     public void setTheme(int resid) {
         mThemeResource = resid;
     }
-    
+
     @Override
     public Resources.Theme getTheme() {
         if (mTheme == null) {
@@ -438,7 +435,7 @@
             }
             if (!mFilesDir.exists()) {
                 if(!mFilesDir.mkdirs()) {
-                    Log.w(TAG, "Unable to create files directory");
+                    Log.w(TAG, "Unable to create files directory " + mFilesDir.getPath());
                     return null;
                 }
                 FileUtils.setPermissions(
@@ -449,7 +446,7 @@
             return mFilesDir;
         }
     }
-    
+
     @Override
     public File getExternalFilesDir(String type) {
         synchronized (mSync) {
@@ -481,7 +478,7 @@
             return dir;
         }
     }
-    
+
     @Override
     public File getCacheDir() {
         synchronized (mSync) {
@@ -501,7 +498,7 @@
         }
         return mCacheDir;
     }
-    
+
     @Override
     public File getExternalCacheDir() {
         synchronized (mSync) {
@@ -523,7 +520,7 @@
             return mExternalCacheDir;
         }
     }
-    
+
     @Override
     public File getFileStreamPath(String name) {
         return makeFilename(getFilesDir(), name);
@@ -564,7 +561,7 @@
         return (list != null) ? list : EMPTY_FILE_LIST;
     }
 
-    
+
     private File getDatabasesDir() {
         synchronized (mSync) {
             if (mDatabasesDir == null) {
@@ -576,7 +573,7 @@
             return mDatabasesDir;
         }
     }
-    
+
     @Override
     public Drawable getWallpaper() {
         return getWallpaperManager().getDrawable();
@@ -644,7 +641,7 @@
         } catch (RemoteException e) {
         }
     }
-    
+
     @Override
     public void sendBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1557,15 +1554,15 @@
     final void setActivityToken(IBinder token) {
         mActivityToken = token;
     }
-    
+
     final void setOuterContext(Context context) {
         mOuterContext = context;
     }
-    
+
     final Context getOuterContext() {
         return mOuterContext;
     }
-    
+
     final IBinder getActivityToken() {
         return mActivityToken;
     }
@@ -1643,7 +1640,7 @@
         public boolean releaseProvider(IContentProvider provider) {
             return mMainThread.releaseProvider(provider);
         }
-        
+
         private final ActivityThread mMainThread;
     }
 
@@ -1676,7 +1673,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public String[] canonicalToCurrentPackageNames(String[] names) {
             try {
@@ -1685,7 +1682,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public Intent getLaunchIntentForPackage(String packageName) {
             // First see if the package has an INFO activity; the existence of
@@ -1707,8 +1704,9 @@
             if (resolveInfo == null) {
                 return null;
             }
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setClassName(packageName, resolveInfo.activityInfo.name);
+            Intent intent = new Intent(intentToResolve);
+            intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName,
+                                resolveInfo.activityInfo.name);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             return intent;
         }
@@ -1874,7 +1872,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public boolean hasSystemFeature(String name) {
             try {
@@ -1883,7 +1881,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public int checkPermission(String permName, String pkgName) {
             try {
@@ -1955,9 +1953,9 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
-        public int getUidForSharedUser(String sharedUserName) 
+        public int getUidForSharedUser(String sharedUserName)
                 throws NameNotFoundException {
             try {
                 int uid = mPM.getUidForSharedUser(sharedUserName);
@@ -2361,7 +2359,7 @@
                 }
             }
         }
-        
+
         private static final class ResourceName {
             final String packageName;
             final int iconId;
@@ -2533,7 +2531,7 @@
             }
         }
         @Override
-        public void clearApplicationUserData(String packageName, 
+        public void clearApplicationUserData(String packageName,
                 IPackageDataObserver observer) {
             try {
                 mPM.clearApplicationUserData(packageName, observer);
@@ -2542,7 +2540,7 @@
             }
         }
         @Override
-        public void deleteApplicationCacheFiles(String packageName, 
+        public void deleteApplicationCacheFiles(String packageName,
                 IPackageDataObserver observer) {
             try {
                 mPM.deleteApplicationCacheFiles(packageName, observer);
@@ -2567,9 +2565,9 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
-        public void getPackageSizeInfo(String packageName, 
+        public void getPackageSizeInfo(String packageName,
                 IPackageStatsObserver observer) {
             try {
                 mPM.getPackageSizeInfo(packageName, observer);
@@ -2614,7 +2612,7 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
         public void replacePreferredActivity(IntentFilter filter,
                 int match, ComponentName[] set, ComponentName activity) {
@@ -2633,7 +2631,7 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
         public int getPreferredActivities(List<IntentFilter> outFilters,
                 List<ComponentName> outActivities, String packageName) {
@@ -2644,7 +2642,7 @@
             }
             return 0;
         }
-        
+
         @Override
         public void setComponentEnabledSetting(ComponentName componentName,
                 int newState, int flags) {
@@ -2674,7 +2672,7 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
         public int getApplicationEnabledSetting(String packageName) {
             try {
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 009671f..8ba480d 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -21,7 +21,6 @@
 import android.content.DialogInterface.OnClickListener;
 import android.os.Bundle;
 import android.text.TextUtils.TruncateAt;
-import android.text.format.DateFormat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.DatePicker;
@@ -39,13 +38,13 @@
  * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker
  * tutorial</a>.</p>
  */
-public class DatePickerDialog extends AlertDialog implements OnClickListener, 
+public class DatePickerDialog extends AlertDialog implements OnClickListener,
         OnDateChangedListener {
 
     private static final String YEAR = "year";
     private static final String MONTH = "month";
     private static final String DAY = "day";
-    
+
     private final DatePicker mDatePicker;
     private final OnDateSetListener mCallBack;
     private final Calendar mCalendar;
@@ -83,7 +82,7 @@
             int year,
             int monthOfYear,
             int dayOfMonth) {
-        this(context, com.android.internal.R.style.Theme_Dialog_Alert, 
+        this(context, com.android.internal.R.style.Theme_Dialog_Alert,
                 callBack, year, monthOfYear, dayOfMonth);
     }
 
@@ -109,17 +108,17 @@
         mInitialDay = dayOfMonth;
         DateFormatSymbols symbols = new DateFormatSymbols();
         mWeekDays = symbols.getShortWeekdays();
-        
+
         mTitleDateFormat = java.text.DateFormat.
                                 getDateInstance(java.text.DateFormat.FULL);
         mCalendar = Calendar.getInstance();
         updateTitle(mInitialYear, mInitialMonth, mInitialDay);
-        
-        setButton(context.getText(R.string.date_time_set), this);
-        setButton2(context.getText(R.string.cancel), (OnClickListener) null);
+
+        setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
+        setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), (OnClickListener) null);
         setIcon(R.drawable.ic_dialog_time);
-        
-        LayoutInflater inflater = 
+
+        LayoutInflater inflater =
                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = inflater.inflate(R.layout.date_picker_dialog, null);
         setView(view);
@@ -139,20 +138,20 @@
         title.setSingleLine();
         title.setEllipsize(TruncateAt.END);
     }
-    
+
     public void onClick(DialogInterface dialog, int which) {
         if (mCallBack != null) {
             mDatePicker.clearFocus();
-            mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(), 
+            mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),
                     mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
         }
     }
-    
+
     public void onDateChanged(DatePicker view, int year,
             int month, int day) {
         updateTitle(year, month, day);
     }
-    
+
     public void updateDate(int year, int monthOfYear, int dayOfMonth) {
         mInitialYear = year;
         mInitialMonth = monthOfYear;
@@ -166,7 +165,7 @@
         mCalendar.set(Calendar.DAY_OF_MONTH, day);
         setTitle(mTitleDateFormat.format(mCalendar.getTime()));
     }
-    
+
     @Override
     public Bundle onSaveInstanceState() {
         Bundle state = super.onSaveInstanceState();
@@ -175,7 +174,7 @@
         state.putInt(DAY, mDatePicker.getDayOfMonth());
         return state;
     }
-    
+
     @Override
     public void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index cd22fa1..1f115e8 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1133,7 +1133,7 @@
         try {
             // If the intent was created from a suggestion, it will always have an explicit
             // component here.
-            Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
+            Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toUri(0));
             getContext().startActivity(intent);
             // If the search switches to a different activity,
             // SearchDialogWrapper#performActivityResuming
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 62d3f7d..521d41c 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -36,7 +36,7 @@
  * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker
  * tutorial</a>.</p>
  */
-public class TimePickerDialog extends AlertDialog implements OnClickListener, 
+public class TimePickerDialog extends AlertDialog implements OnClickListener,
         OnTimeChangedListener {
 
     /**
@@ -56,12 +56,12 @@
     private static final String HOUR = "hour";
     private static final String MINUTE = "minute";
     private static final String IS_24_HOUR = "is24hour";
-    
+
     private final TimePicker mTimePicker;
     private final OnTimeSetListener mCallback;
     private final Calendar mCalendar;
     private final java.text.DateFormat mDateFormat;
-    
+
     int mInitialHourOfDay;
     int mInitialMinute;
     boolean mIs24HourView;
@@ -101,12 +101,13 @@
         mDateFormat = DateFormat.getTimeFormat(context);
         mCalendar = Calendar.getInstance();
         updateTitle(mInitialHourOfDay, mInitialMinute);
-        
-        setButton(context.getText(R.string.date_time_set), this);
-        setButton2(context.getText(R.string.cancel), (OnClickListener) null);
+
+        setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
+        setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel),
+                (OnClickListener) null);
         setIcon(R.drawable.ic_dialog_time);
-        
-        LayoutInflater inflater = 
+
+        LayoutInflater inflater =
                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = inflater.inflate(R.layout.time_picker_dialog, null);
         setView(view);
@@ -118,11 +119,11 @@
         mTimePicker.setIs24HourView(mIs24HourView);
         mTimePicker.setOnTimeChangedListener(this);
     }
-    
+
     public void onClick(DialogInterface dialog, int which) {
         if (mCallback != null) {
             mTimePicker.clearFocus();
-            mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(), 
+            mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                     mTimePicker.getCurrentMinute());
         }
     }
@@ -130,7 +131,7 @@
     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
         updateTitle(hourOfDay, minute);
     }
-    
+
     public void updateTime(int hourOfDay, int minutOfHour) {
         mTimePicker.setCurrentHour(hourOfDay);
         mTimePicker.setCurrentMinute(minutOfHour);
@@ -141,7 +142,7 @@
         mCalendar.set(Calendar.MINUTE, minute);
         setTitle(mDateFormat.format(mCalendar.getTime()));
     }
-    
+
     @Override
     public Bundle onSaveInstanceState() {
         Bundle state = super.onSaveInstanceState();
@@ -150,7 +151,7 @@
         state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView());
         return state;
     }
-    
+
     @Override
     public void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e455a59..92b7cf5 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -235,8 +235,13 @@
                     if (width <= 0 || height <= 0) {
                         // Degenerate case: no size requested, just load
                         // bitmap as-is.
-                        Bitmap bm = BitmapFactory.decodeFileDescriptor(
-                                fd.getFileDescriptor(), null, null);
+                        Bitmap bm = null;
+                        try {
+                            bm = BitmapFactory.decodeFileDescriptor(
+                                   fd.getFileDescriptor(), null, null);
+                        } catch (OutOfMemoryError e) {
+                            Log.w(TAG, "Can't decode file", e);
+                        }
                         try {
                             fd.close();
                         } catch (IOException e) {
@@ -277,7 +282,12 @@
                     if (width <= 0 || height <= 0) {
                         // Degenerate case: no size requested, just load
                         // bitmap as-is.
-                        Bitmap bm = BitmapFactory.decodeStream(is, null, null);
+                        Bitmap bm = null;
+                        try {
+                            bm = BitmapFactory.decodeStream(is, null, null);
+                        } catch (OutOfMemoryError e) {
+                            Log.w(TAG, "Can't decode stream", e);
+                        }
                         try {
                             is.close();
                         } catch (IOException e) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index d4ce6a1..d2ab85e 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -22,7 +22,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.util.TypedValue;
 import android.widget.RemoteViews;
 
@@ -149,7 +148,7 @@
      *     instances as possible.</td>
      *  </tr>
      * </table>
-     * 
+     *
      * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
      */
     public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
@@ -163,7 +162,7 @@
 
     /**
      * Sent when an instance of an AppWidget is removed from the last host.
-     * 
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
@@ -172,7 +171,7 @@
      * Sent when an instance of an AppWidget is added to a host for the first time.
      * This broadcast is sent at boot time if there is a AppWidgetHost installed with
      * an instance for this provider.
-     * 
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
@@ -183,20 +182,21 @@
      * @see AppWidgetProviderInfo
      */
     public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
-    
+
     /**
      * Field for the manifest meta-data tag used to indicate any previous name for the
      * app widget receiver.
      *
      * @see AppWidgetProviderInfo
-     * 
+     *
      * @hide Pending API approval
      */
     public static final String META_DATA_APPWIDGET_OLD_NAME = "android.appwidget.oldName";
 
-    static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap();
+    static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache =
+        new WeakHashMap<Context, WeakReference<AppWidgetManager>>();
     static IAppWidgetService sService;
-    
+
     Context mContext;
 
     private DisplayMetrics mDisplayMetrics;
@@ -219,7 +219,7 @@
             }
             if (result == null) {
                 result = new AppWidgetManager(context);
-                sManagerCache.put(context, new WeakReference(result));
+                sManagerCache.put(context, new WeakReference<AppWidgetManager>(result));
             }
             return result;
         }
@@ -310,7 +310,7 @@
             AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
             if (info != null) {
                 // Converting complex to dp.
-                info.minWidth = 
+                info.minWidth =
                         TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
                 info.minHeight =
                         TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
@@ -344,7 +344,7 @@
     /**
      * Get the list of appWidgetIds that have been bound to the given AppWidget
      * provider.
-     * 
+     *
      * @param provider The {@link android.content.BroadcastReceiver} that is the
      *            AppWidget provider to find appWidgetIds for.
      */
diff --git a/core/java/android/bluetooth/AtCommandHandler.java b/core/java/android/bluetooth/AtCommandHandler.java
index 8de2133..6deab34 100644
--- a/core/java/android/bluetooth/AtCommandHandler.java
+++ b/core/java/android/bluetooth/AtCommandHandler.java
@@ -73,7 +73,7 @@
      *             least one element in this array.
      * @return     The result of this command.
      */
-    // Typically used to set this paramter
+    // Typically used to set this parameter
     public AtCommandResult handleSetCommand(Object[] args) {
         return new AtCommandResult(AtCommandResult.ERROR);
     }
@@ -83,11 +83,12 @@
      * Test commands are part of the Extended command syntax, and are typically
      * used to request an indication of the range of legal values that "FOO"
      * can take.<p>
-     * By defualt we return an OK result, to indicate that this command is at
+     * By default we return an OK result, to indicate that this command is at
      * least recognized.<p>
      * @return The result of this command.
      */
     public AtCommandResult handleTestCommand() {
         return new AtCommandResult(AtCommandResult.OK);
     }
+
 }
diff --git a/core/java/android/bluetooth/BluetoothAssignedNumbers.java b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
new file mode 100644
index 0000000..55bc814
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * Bluetooth Assigned Numbers.
+ * <p>
+ * For now we only include Company ID values.
+ * @see <a href="https://www.bluetooth.org/technical/assignednumbers/identifiers.htm">
+ * The Official Bluetooth SIG Member Website | Company Identifiers</a>
+ *
+ * @hide
+ */
+public class BluetoothAssignedNumbers {
+
+    //// Bluetooth SIG Company ID values
+
+    /*
+     * Ericsson Technology Licensing.
+     */
+    public static final int ERICSSON_TECHNOLOGY = 0x0000;
+
+    /*
+     * Nokia Mobile Phones.
+     */
+    public static final int NOKIA_MOBILE_PHONES = 0x0001;
+
+    /*
+     * Intel Corp.
+     */
+    public static final int INTEL = 0x0002;
+
+    /*
+     * IBM Corp.
+     */
+    public static final int IBM = 0x0003;
+
+    /*
+     * Toshiba Corp.
+     */
+    public static final int TOSHIBA = 0x0004;
+
+    /*
+     * 3Com.
+     */
+    public static final int THREECOM = 0x0005;
+
+    /*
+     * Microsoft.
+     */
+    public static final int MICROSOFT = 0x0006;
+
+    /*
+     * Lucent.
+     */
+    public static final int LUCENT = 0x0007;
+
+    /*
+     * Motorola.
+     */
+    public static final int MOTOROLA = 0x0008;
+
+    /*
+     * Infineon Technologies AG.
+     */
+    public static final int INFINEON_TECHNOLOGIES = 0x0009;
+
+    /*
+     * Cambridge Silicon Radio.
+     */
+    public static final int CAMBRIDGE_SILICON_RADIO = 0x000A;
+
+    /*
+     * Silicon Wave.
+     */
+    public static final int SILICON_WAVE = 0x000B;
+
+    /*
+     * Digianswer A/S.
+     */
+    public static final int DIGIANSWER = 0x000C;
+
+    /*
+     * Texas Instruments Inc.
+     */
+    public static final int TEXAS_INSTRUMENTS = 0x000D;
+
+    /*
+     * Parthus Technologies Inc.
+     */
+    public static final int PARTHUS_TECHNOLOGIES = 0x000E;
+
+    /*
+     * Broadcom Corporation.
+     */
+    public static final int BROADCOM = 0x000F;
+
+    /*
+     * Mitel Semiconductor.
+     */
+    public static final int MITEL_SEMICONDUCTOR = 0x0010;
+
+    /*
+     * Widcomm, Inc.
+     */
+    public static final int WIDCOMM = 0x0011;
+
+    /*
+     * Zeevo, Inc.
+     */
+    public static final int ZEEVO = 0x0012;
+
+    /*
+     * Atmel Corporation.
+     */
+    public static final int ATMEL = 0x0013;
+
+    /*
+     * Mitsubishi Electric Corporation.
+     */
+    public static final int MITSUBISHI_ELECTRIC = 0x0014;
+
+    /*
+     * RTX Telecom A/S.
+     */
+    public static final int RTX_TELECOM = 0x0015;
+
+    /*
+     * KC Technology Inc.
+     */
+    public static final int KC_TECHNOLOGY = 0x0016;
+
+    /*
+     * Newlogic.
+     */
+    public static final int NEWLOGIC = 0x0017;
+
+    /*
+     * Transilica, Inc.
+     */
+    public static final int TRANSILICA = 0x0018;
+
+    /*
+     * Rohde & Schwarz GmbH & Co. KG.
+     */
+    public static final int ROHDE_AND_SCHWARZ = 0x0019;
+
+    /*
+     * TTPCom Limited.
+     */
+    public static final int TTPCOM = 0x001A;
+
+    /*
+     * Signia Technologies, Inc.
+     */
+    public static final int SIGNIA_TECHNOLOGIES = 0x001B;
+
+    /*
+     * Conexant Systems Inc.
+     */
+    public static final int CONEXANT_SYSTEMS = 0x001C;
+
+    /*
+     * Qualcomm.
+     */
+    public static final int QUALCOMM = 0x001D;
+
+    /*
+     * Inventel.
+     */
+    public static final int INVENTEL = 0x001E;
+
+    /*
+     * AVM Berlin.
+     */
+    public static final int AVM_BERLIN = 0x001F;
+
+    /*
+     * BandSpeed, Inc.
+     */
+    public static final int BANDSPEED = 0x0020;
+
+    /*
+     * Mansella Ltd.
+     */
+    public static final int MANSELLA = 0x0021;
+
+    /*
+     * NEC Corporation.
+     */
+    public static final int NEC = 0x0022;
+
+    /*
+     * WavePlus Technology Co., Ltd.
+     */
+    public static final int WAVEPLUS_TECHNOLOGY = 0x0023;
+
+    /*
+     * Alcatel.
+     */
+    public static final int ALCATEL = 0x0024;
+
+    /*
+     * Philips Semiconductors.
+     */
+    public static final int PHILIPS_SEMICONDUCTORS = 0x0025;
+
+    /*
+     * C Technologies.
+     */
+    public static final int C_TECHNOLOGIES = 0x0026;
+
+    /*
+     * Open Interface.
+     */
+    public static final int OPEN_INTERFACE = 0x0027;
+
+    /*
+     * R F Micro Devices.
+     */
+    public static final int RF_MICRO_DEVICES = 0x0028;
+
+    /*
+     * Hitachi Ltd.
+     */
+    public static final int HITACHI = 0x0029;
+
+    /*
+     * Symbol Technologies, Inc.
+     */
+    public static final int SYMBOL_TECHNOLOGIES = 0x002A;
+
+    /*
+     * Tenovis.
+     */
+    public static final int TENOVIS = 0x002B;
+
+    /*
+     * Macronix International Co. Ltd.
+     */
+    public static final int MACRONIX = 0x002C;
+
+    /*
+     * GCT Semiconductor.
+     */
+    public static final int GCT_SEMICONDUCTOR = 0x002D;
+
+    /*
+     * Norwood Systems.
+     */
+    public static final int NORWOOD_SYSTEMS = 0x002E;
+
+    /*
+     * MewTel Technology Inc.
+     */
+    public static final int MEWTEL_TECHNOLOGY = 0x002F;
+
+    /*
+     * ST Microelectronics.
+     */
+    public static final int ST_MICROELECTRONICS = 0x0030;
+
+    /*
+     * Synopsys.
+     */
+    public static final int SYNOPSYS = 0x0031;
+
+    /*
+     * Red-M (Communications) Ltd.
+     */
+    public static final int RED_M = 0x0032;
+
+    /*
+     * Commil Ltd.
+     */
+    public static final int COMMIL = 0x0033;
+
+    /*
+     * Computer Access Technology Corporation (CATC).
+     */
+    public static final int CATC = 0x0034;
+
+    /*
+     * Eclipse (HQ Espana) S.L.
+     */
+    public static final int ECLIPSE = 0x0035;
+
+    /*
+     * Renesas Technology Corp.
+     */
+    public static final int RENESAS_TECHNOLOGY = 0x0036;
+
+    /*
+     * Mobilian Corporation.
+     */
+    public static final int MOBILIAN_CORPORATION = 0x0037;
+
+    /*
+     * Terax.
+     */
+    public static final int TERAX = 0x0038;
+
+    /*
+     * Integrated System Solution Corp.
+     */
+    public static final int INTEGRATED_SYSTEM_SOLUTION = 0x0039;
+
+    /*
+     * Matsushita Electric Industrial Co., Ltd.
+     */
+    public static final int MATSUSHITA_ELECTRIC = 0x003A;
+
+    /*
+     * Gennum Corporation.
+     */
+    public static final int GENNUM = 0x003B;
+
+    /*
+     * Research In Motion.
+     */
+    public static final int RESEARCH_IN_MOTION = 0x003C;
+
+    /*
+     * IPextreme, Inc.
+     */
+    public static final int IPEXTREME = 0x003D;
+
+    /*
+     * Systems and Chips, Inc.
+     */
+    public static final int SYSTEMS_AND_CHIPS = 0x003E;
+
+    /*
+     * Bluetooth SIG, Inc.
+     */
+    public static final int BLUETOOTH_SIG = 0x003F;
+
+    /*
+     * Seiko Epson Corporation.
+     */
+    public static final int SEIKO_EPSON = 0x0040;
+
+    /*
+     * Integrated Silicon Solution Taiwan, Inc.
+     */
+    public static final int INTEGRATED_SILICON_SOLUTION = 0x0041;
+
+    /*
+     * CONWISE Technology Corporation Ltd.
+     */
+    public static final int CONWISE_TECHNOLOGY = 0x0042;
+
+    /*
+     * PARROT SA.
+     */
+    public static final int PARROT = 0x0043;
+
+    /*
+     * Socket Mobile.
+     */
+    public static final int SOCKET_MOBILE = 0x0044;
+
+    /*
+     * Atheros Communications, Inc.
+     */
+    public static final int ATHEROS_COMMUNICATIONS = 0x0045;
+
+    /*
+     * MediaTek, Inc.
+     */
+    public static final int MEDIATEK = 0x0046;
+
+    /*
+     * Bluegiga.
+     */
+    public static final int BLUEGIGA = 0x0047;
+
+    /*
+     * Marvell Technology Group Ltd.
+     */
+    public static final int MARVELL = 0x0048;
+
+    /*
+     * 3DSP Corporation.
+     */
+    public static final int THREE_DSP = 0x0049;
+
+    /*
+     * Accel Semiconductor Ltd.
+     */
+    public static final int ACCEL_SEMICONDUCTOR = 0x004A;
+
+    /*
+     * Continental Automotive Systems.
+     */
+    public static final int CONTINENTAL_AUTOMOTIVE = 0x004B;
+
+    /*
+     * Apple, Inc.
+     */
+    public static final int APPLE = 0x004C;
+
+    /*
+     * Staccato Communications, Inc.
+     */
+    public static final int STACCATO_COMMUNICATIONS = 0x004D;
+
+    /*
+     * Avago Technologies.
+     */
+    public static final int AVAGO = 0x004E;
+
+    /*
+     * APT Licensing Ltd.
+     */
+    public static final int APT_LICENSING = 0x004F;
+
+    /*
+     * SiRF Technology, Inc.
+     */
+    public static final int SIRF_TECHNOLOGY = 0x0050;
+
+    /*
+     * Tzero Technologies, Inc.
+     */
+    public static final int TZERO_TECHNOLOGIES = 0x0051;
+
+    /*
+     * J&M Corporation.
+     */
+    public static final int J_AND_M = 0x0052;
+
+    /*
+     * Free2move AB.
+     */
+    public static final int FREE2MOVE = 0x0053;
+
+    /*
+     * 3DiJoy Corporation.
+     */
+    public static final int THREE_DIJOY = 0x0054;
+
+    /*
+     * Plantronics, Inc.
+     */
+    public static final int PLANTRONICS = 0x0055;
+
+    /*
+     * Sony Ericsson Mobile Communications.
+     */
+    public static final int SONY_ERICSSON = 0x0056;
+
+    /*
+     * Harman International Industries, Inc.
+     */
+    public static final int HARMAN_INTERNATIONAL = 0x0057;
+
+    /*
+     * Vizio, Inc.
+     */
+    public static final int VIZIO = 0x0058;
+
+    /*
+     * Nordic Semiconductor ASA.
+     */
+    public static final int NORDIC_SEMICONDUCTOR = 0x0059;
+
+    /*
+     * EM Microelectronic-Marin SA.
+     */
+    public static final int EM_MICROELECTRONIC_MARIN = 0x005A;
+
+    /*
+     * Ralink Technology Corporation.
+     */
+    public static final int RALINK_TECHNOLOGY = 0x005B;
+
+    /*
+     * Belkin International, Inc.
+     */
+    public static final int BELKIN_INTERNATIONAL = 0x005C;
+
+    /*
+     * Realtek Semiconductor Corporation.
+     */
+    public static final int REALTEK_SEMICONDUCTOR = 0x005D;
+
+    /*
+     * Stonestreet One, LLC.
+     */
+    public static final int STONESTREET_ONE = 0x005E;
+
+    /*
+     * Wicentric, Inc.
+     */
+    public static final int WICENTRIC = 0x005F;
+
+    /*
+     * RivieraWaves S.A.S.
+     */
+    public static final int RIVIERAWAVES = 0x0060;
+
+    /*
+     * You can't instantiate one of these.
+     */
+    private BluetoothAssignedNumbers() {
+    }
+
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 197b022..da1aa45 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -85,6 +85,43 @@
             "android.bluetooth.headset.extra.DISCONNECT_INITIATOR";
 
     /**
+     * Broadcast Action: Indicates a headset has posted a vendor-specific event.
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE},
+     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD}, and
+     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
+            "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
+
+    /**
+     * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
+     * intents that contains the name of the vendor-specific command.
+     */
+    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD =
+            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
+
+    /**
+     * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
+     * intents that contains the Company ID of the vendor defining the vendor-specific
+     * command.
+     * @see <a href="https://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm">
+     * Bluetooth SIG Assigned Numbers - Company Identifiers</a>
+     */
+    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID =
+            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID";
+
+    /**
+     * A Parcelable String array extra field in
+     * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains
+     * the arguments to the vendor-specific command.
+     */
+    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS =
+            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
+
+
+    /**
      * TODO(API release): Consider incorporating as new state in
      * HEADSET_STATE_CHANGED
      */
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index 22495a7..9ef2eb5 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -74,8 +74,8 @@
 
     private native void cleanupNativeDataNative();
 
-    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
-            int rfcommChannel) {
+    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter,
+                       BluetoothDevice device, int rfcommChannel) {
         mDirection = DIRECTION_OUTGOING;
         mConnectTimestamp = System.currentTimeMillis();
         mAdapter = adapter;
@@ -89,9 +89,10 @@
         initializeNativeDataNative(-1);
     }
 
-    /* Create from an already existing rfcomm connection */
-    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
-            int socketFd, int rfcommChannel, Handler handler) {
+    /* Create from an existing rfcomm connection */
+    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter,
+                       BluetoothDevice device,
+                       int socketFd, int rfcommChannel, Handler handler) {
         mDirection = DIRECTION_INCOMING;
         mConnectTimestamp = System.currentTimeMillis();
         mAdapter = adapter;
@@ -142,8 +143,9 @@
      */
     protected void initializeAtParser() {
         mAtParser = new AtParser();
-        //TODO(): Get rid of this as there are no parsers registered. But because of dependencies,
-        //it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree
+
+        //TODO(): Get rid of this as there are no parsers registered. But because of dependencies
+        // it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree
     }
 
     public AtParser getAtParser() {
@@ -159,8 +161,7 @@
                         String input = readNative(500);
                         if (input != null) {
                             handleInput(input);
-                        }
-                        else {
+                        } else {
                             last_read_error = getLastReadStatusNative();
                             if (last_read_error != 0) {
                                 Log.i(TAG, "headset read error " + last_read_error);
@@ -179,8 +180,6 @@
         mEventThread.start();
     }
 
-
-
     private native String readNative(int timeout_ms);
     private native int getLastReadStatusNative();
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
old mode 100644
new mode 100755
index 9bb3b75..a6513aa
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -25,6 +25,7 @@
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable.ConstantState;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemProperties;
@@ -66,6 +67,8 @@
             = new LongSparseArray<Drawable.ConstantState>();
     private static final SparseArray<ColorStateList> mPreloadedColorStateLists
             = new SparseArray<ColorStateList>();
+    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
+            = new LongSparseArray<Drawable.ConstantState>();
     private static boolean mPreloaded;
 
     /*package*/ final TypedValue mTmpValue = new TypedValue();
@@ -75,6 +78,8 @@
             = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
     private final SparseArray<WeakReference<ColorStateList> > mColorStateListCache
             = new SparseArray<WeakReference<ColorStateList> >();
+    private final LongSparseArray<WeakReference<Drawable.ConstantState> > mColorDrawableCache
+            = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
     private boolean mPreloading;
 
     /*package*/ TypedArray mCachedStyledAttributes = null;
@@ -1299,37 +1304,13 @@
                     (int)(mMetrics.density*160), mConfiguration.keyboard,
                     keyboardHidden, mConfiguration.navigation, width, height,
                     mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion);
-            int N = mDrawableCache.size();
-            if (DEBUG_CONFIG) {
-                Log.d(TAG, "Cleaning up drawables config changes: 0x"
-                        + Integer.toHexString(configChanges));
-            }
-            for (int i=0; i<N; i++) {
-                WeakReference<Drawable.ConstantState> ref = mDrawableCache.valueAt(i);
-                if (ref != null) {
-                    Drawable.ConstantState cs = ref.get();
-                    if (cs != null) {
-                        if (Configuration.needNewResources(
-                                configChanges, cs.getChangingConfigurations())) {
-                            if (DEBUG_CONFIG) {
-                                Log.d(TAG, "FLUSHING #0x"
-                                        + Long.toHexString(mDrawableCache.keyAt(i))
-                                        + " / " + cs + " with changes: 0x"
-                                        + Integer.toHexString(cs.getChangingConfigurations()));
-                            }
-                            mDrawableCache.setValueAt(i, null);
-                        } else if (DEBUG_CONFIG) {
-                            Log.d(TAG, "(Keeping #0x"
-                                    + Long.toHexString(mDrawableCache.keyAt(i))
-                                    + " / " + cs + " with changes: 0x"
-                                    + Integer.toHexString(cs.getChangingConfigurations())
-                                    + ")");
-                        }
-                    }
-                }
-            }
-            mDrawableCache.clear();
+
+            clearDrawableCache(mDrawableCache, configChanges);
+            clearDrawableCache(mColorDrawableCache, configChanges);
+
             mColorStateListCache.clear();
+
+
             flushLayoutCache();
         }
         synchronized (mSync) {
@@ -1339,6 +1320,41 @@
         }
     }
 
+    private void clearDrawableCache(
+            LongSparseArray<WeakReference<ConstantState>> cache,
+            int configChanges) {
+        int N = cache.size();
+        if (DEBUG_CONFIG) {
+            Log.d(TAG, "Cleaning up drawables config changes: 0x"
+                    + Integer.toHexString(configChanges));
+        }
+        for (int i=0; i<N; i++) {
+            WeakReference<Drawable.ConstantState> ref = cache.valueAt(i);
+            if (ref != null) {
+                Drawable.ConstantState cs = ref.get();
+                if (cs != null) {
+                    if (Configuration.needNewResources(
+                            configChanges, cs.getChangingConfigurations())) {
+                        if (DEBUG_CONFIG) {
+                            Log.d(TAG, "FLUSHING #0x"
+                                    + Long.toHexString(mDrawableCache.keyAt(i))
+                                    + " / " + cs + " with changes: 0x"
+                                    + Integer.toHexString(cs.getChangingConfigurations()));
+                        }
+                        cache.setValueAt(i, null);
+                    } else if (DEBUG_CONFIG) {
+                        Log.d(TAG, "(Keeping #0x"
+                                + Long.toHexString(cache.keyAt(i))
+                                + " / " + cs + " with changes: 0x"
+                                + Integer.toHexString(cs.getChangingConfigurations())
+                                + ")");
+                    }
+                }
+            }
+        }
+        cache.clear();
+    }
+
     /**
      * Update the system resources configuration if they have previously
      * been initialized.
@@ -1661,13 +1677,18 @@
         }
 
         final long key = (((long) value.assetCookie) << 32) | value.data;
-        Drawable dr = getCachedDrawable(key);
+        boolean isColorDrawable = false;
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
+                value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            isColorDrawable = true;
+        }
+        Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
 
         if (dr != null) {
             return dr;
         }
 
-        Drawable.ConstantState cs = sPreloadedDrawables.get(key);
+        Drawable.ConstantState cs = isColorDrawable ? sPreloadedColorDrawables.get(key) : sPreloadedDrawables.get(key);
         if (cs != null) {
             dr = cs.newDrawable(this);
         } else {
@@ -1726,13 +1747,21 @@
             cs = dr.getConstantState();
             if (cs != null) {
                 if (mPreloading) {
-                    sPreloadedDrawables.put(key, cs);
+                    if (isColorDrawable) {
+                        sPreloadedColorDrawables.put(key, cs);
+                    } else {
+                        sPreloadedDrawables.put(key, cs);
+                    }
                 } else {
                     synchronized (mTmpValue) {
                         //Log.i(TAG, "Saving cached drawable @ #" +
                         //        Integer.toHexString(key.intValue())
                         //        + " in " + this + ": " + cs);
-                        mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+                        if (isColorDrawable) {
+                            mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+                        } else {
+                            mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+                        }
                     }
                 }
             }
@@ -1741,9 +1770,11 @@
         return dr;
     }
 
-    private Drawable getCachedDrawable(long key) {
+    private Drawable getCachedDrawable(
+            LongSparseArray<WeakReference<ConstantState>> drawableCache,
+            long key) {
         synchronized (mTmpValue) {
-            WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
+            WeakReference<Drawable.ConstantState> wr = drawableCache.get(key);
             if (wr != null) {   // we have the key
                 Drawable.ConstantState entry = wr.get();
                 if (entry != null) {
@@ -1753,7 +1784,7 @@
                     return entry.newDrawable(this);
                 }
                 else {  // our entry has been purged
-                    mDrawableCache.delete(key);
+                    drawableCache.delete(key);
                 }
             }
         }
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 038eedf..a5e5e46 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -204,7 +204,7 @@
      * @param window
      */
     public void fillWindow(int position, CursorWindow window) {
-        if (position < 0 || position > getCount()) {
+        if (position < 0 || position >= getCount()) {
             return;
         }
         window.acquireReference();
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 66406ca..95fc1fd 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -50,8 +50,6 @@
     private static final boolean DEBUG = false;
     private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
 
-    private static final String[] countProjection = new String[]{"count(*)"};
-
     /**
      * Special function for writing an exception result at the header of
      * a parcel, to be used when returning an exception from a transaction.
@@ -604,14 +602,40 @@
      * @return the number of rows in the table
      */
     public static long queryNumEntries(SQLiteDatabase db, String table) {
-        Cursor cursor = db.query(table, countProjection,
-                null, null, null, null, null);
-        try {
-            cursor.moveToFirst();
-            return cursor.getLong(0);
-        } finally {
-            cursor.close();
-        }
+        return queryNumEntries(db, table, null, null);
+    }
+
+    /**
+     * Query the table for the number of rows in the table.
+     * @param db the database the table is in
+     * @param table the name of the table to query
+     * @param selection A filter declaring which rows to return,
+     *              formatted as an SQL WHERE clause (excluding the WHERE itself).
+     *              Passing null will count all rows for the given table
+     * @return the number of rows in the table filtered by the selection
+     */
+    public static long queryNumEntries(SQLiteDatabase db, String table, String selection) {
+        return queryNumEntries(db, table, selection, null);
+    }
+
+    /**
+     * Query the table for the number of rows in the table.
+     * @param db the database the table is in
+     * @param table the name of the table to query
+     * @param selection A filter declaring which rows to return,
+     *              formatted as an SQL WHERE clause (excluding the WHERE itself).
+     *              Passing null will count all rows for the given table
+     * @param selectionArgs You may include ?s in selection,
+     *              which will be replaced by the values from selectionArgs,
+     *              in order that they appear in the selection.
+     *              The values will be bound as Strings.
+     * @return the number of rows in the table filtered by the selection
+     */
+    public static long queryNumEntries(SQLiteDatabase db, String table, String selection,
+            String[] selectionArgs) {
+        String s = (!TextUtils.isEmpty(selection)) ? " where " + selection : "";
+        return longForQuery(db, "select count(*) from " + table + s,
+                    selectionArgs);
     }
 
     /**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 39681912..1cfe419b7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -21,6 +21,9 @@
 import android.os.Binder;
 import android.os.RemoteException;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 /**
  * Class that answers queries about the state of network connectivity. It also
  * notifies applications when network connectivity changes. Get an instance
@@ -328,8 +331,29 @@
      * @return {@code true} on success, {@code false} on failure
      */
     public boolean requestRouteToHost(int networkType, int hostAddress) {
+        InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
+
+        if (inetAddress == null) {
+            return false;
+        }
+
+        return requestRouteToHostAddress(networkType, inetAddress);
+    }
+
+    /**
+     * Ensure that a network route exists to deliver traffic to the specified
+     * host via the specified network interface. An attempt to add a route that
+     * already exists is ignored, but treated as successful.
+     * @param networkType the type of the network over which traffic to the specified
+     * host is to be routed
+     * @param hostAddress the IP address of the host to which the route is desired
+     * @return {@code true} on success, {@code false} on failure
+     * @hide
+     */
+    public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
+        byte[] address = hostAddress.getAddress();
         try {
-            return mService.requestRouteToHost(networkType, hostAddress);
+            return mService.requestRouteToHostAddress(networkType, address);
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b734ac7..afccdd9 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -47,6 +47,8 @@
 
     boolean requestRouteToHost(int networkType, int hostAddress);
 
+    boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
+
     boolean getBackgroundDataSetting();
 
     void setBackgroundDataSetting(boolean allowBackgroundData);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index ffbd69d..8d18eba 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import java.net.InetAddress;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -23,7 +25,6 @@
 import android.os.RemoteException;
 import android.os.Handler;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyIntents;
@@ -489,17 +490,16 @@
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the mobile data network.
      * @param hostAddress the IP address of the host to which the route is desired,
-     * in network byte order.
      * @return {@code true} on success, {@code false} on failure
      */
     @Override
-    public boolean requestRouteToHost(int hostAddress) {
+    public boolean requestRouteToHost(InetAddress hostAddress) {
         if (DBG) {
-            Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) +
+            Log.d(TAG, "Requested host route to " + hostAddress.getHostAddress() +
                     " for " + mApnType + "(" + mInterfaceName + ")");
         }
-        if (mInterfaceName != null && hostAddress != -1) {
-            return NetworkUtils.addHostRoute(mInterfaceName, hostAddress) == 0;
+        if (mInterfaceName != null) {
+            return NetworkUtils.addHostRoute(mInterfaceName, hostAddress, null);
         } else {
             return false;
         }
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index d340a99..c161f3a 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -18,13 +18,14 @@
 
 import java.io.FileWriter;
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
 import android.content.Context;
 import android.text.TextUtils;
-import android.util.Config;
 import android.util.Log;
 
 
@@ -133,13 +134,18 @@
         }
         if (mInterfaceName != null && !mPrivateDnsRouteSet) {
             for (String addrString : getNameServers()) {
-                int addr = NetworkUtils.lookupHost(addrString);
-                if (addr != -1 && addr != 0) {
-                    if (DBG) Log.d(TAG, "  adding "+addrString+" ("+addr+")");
-                    NetworkUtils.addHostRoute(mInterfaceName, addr);
+                if (addrString != null) {
+                    try {
+                        InetAddress inetAddress = InetAddress.getByName(addrString);
+                        if (DBG) Log.d(TAG, "  adding " + addrString);
+                        if (NetworkUtils.addHostRoute(mInterfaceName, inetAddress, null)) {
+                            mPrivateDnsRouteSet = true;
+                        }
+                    } catch (UnknownHostException e) {
+                        if (DBG) Log.d(TAG, " DNS address " + addrString + " : Exception " + e);
+                    }
                 }
             }
-            mPrivateDnsRouteSet = true;
         }
     }
 
@@ -162,7 +168,14 @@
                 Log.d(TAG, "addDefaultRoute for " + mNetworkInfo.getTypeName() +
                         " (" + mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr);
             }
-            NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr);
+            InetAddress inetAddress = NetworkUtils.intToInetAddress(mDefaultGatewayAddr);
+            if (inetAddress == null) {
+                if (DBG) Log.d(TAG, " Unable to add default route. mDefaultGatewayAddr Error");
+            } else {
+                if (!NetworkUtils.addDefaultRoute(mInterfaceName, inetAddress) && DBG) {
+                    Log.d(TAG, "  Unable to add default route.");
+                }
+            }
         }
     }
 
@@ -399,7 +412,7 @@
      * @param hostAddress the IP address of the host to which the route is desired
      * @return {@code true} on success, {@code false} on failure
      */
-    public boolean requestRouteToHost(int hostAddress) {
+    public boolean requestRouteToHost(InetAddress hostAddress) {
         return false;
     }
 
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index e4f3d5c..5d4b099 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -17,25 +17,39 @@
 package android.net;
 
 import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.UnknownHostException;
 
+import android.util.Log;
+
 /**
  * Native methods for managing network interfaces.
  *
  * {@hide}
  */
 public class NetworkUtils {
+
+    private static final String TAG = "NetworkUtils";
+
     /** Bring the named network interface up. */
     public native static int enableInterface(String interfaceName);
 
     /** Bring the named network interface down. */
     public native static int disableInterface(String interfaceName);
 
-    /** Add a route to the specified host via the named interface. */
-    public native static int addHostRoute(String interfaceName, int hostaddr);
-
-    /** Add a default route for the named interface. */
-    public native static int setDefaultRoute(String interfaceName, int gwayAddr);
+    /**
+     * Add a route to the routing table.
+     *
+     * @param interfaceName the interface to route through.
+     * @param dst the network or host to route to. May be IPv4 or IPv6, e.g.
+     * "0.0.0.0" or "2001:4860::".
+     * @param prefixLength the prefix length of the route.
+     * @param gw the gateway to use, e.g., "192.168.251.1". If null,
+     * indicates a directly-connected route.
+     */
+    public native static int addRoute(String interfaceName, String dst,
+          int prefixLength, String gw);
 
     /** Return the gateway address for the default route for the named interface. */
     public native static int getDefaultRoute(String interfaceName);
@@ -106,27 +120,79 @@
         String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2);
 
     /**
-     * Look up a host name and return the result as an int. Works if the argument
-     * is an IP address in dot notation. Obviously, this can only be used for IPv4
-     * addresses.
-     * @param hostname the name of the host (or the IP address)
-     * @return the IP address as an {@code int} in network byte order
+     * Convert a IPv4 address from an integer to an InetAddress.
+     * @param hostAddr is an Int corresponding to the IPv4 address in network byte order
+     * @return the IP address as an {@code InetAddress}, returns null if
+     * unable to convert or if the int is an invalid address.
      */
-    public static int lookupHost(String hostname) {
+    public static InetAddress intToInetAddress(int hostAddress) {
         InetAddress inetAddress;
+        byte[] addressBytes = { (byte)(0xff & hostAddress),
+                                (byte)(0xff & (hostAddress >> 8)),
+                                (byte)(0xff & (hostAddress >> 16)),
+                                (byte)(0xff & (hostAddress >> 24)) };
+
         try {
-            inetAddress = InetAddress.getByName(hostname);
-        } catch (UnknownHostException e) {
-            return -1;
+           inetAddress = InetAddress.getByAddress(addressBytes);
+        } catch(UnknownHostException e) {
+           return null;
         }
-        byte[] addrBytes;
-        int addr;
-        addrBytes = inetAddress.getAddress();
-        addr = ((addrBytes[3] & 0xff) << 24)
-                | ((addrBytes[2] & 0xff) << 16)
-                | ((addrBytes[1] & 0xff) << 8)
-                |  (addrBytes[0] & 0xff);
-        return addr;
+
+        return inetAddress;
+    }
+
+    /**
+     * Add a default route through the specified gateway.
+     * @param interfaceName interface on which the route should be added
+     * @param gw the IP address of the gateway to which the route is desired,
+     * @return {@code true} on success, {@code false} on failure
+     */
+    public static boolean addDefaultRoute(String interfaceName, InetAddress gw) {
+        String dstStr;
+        String gwStr = gw.getHostAddress();
+
+        if (gw instanceof Inet4Address) {
+            dstStr = "0.0.0.0";
+        } else if (gw instanceof Inet6Address) {
+            dstStr = "::";
+        } else {
+            Log.w(TAG, "addDefaultRoute failure: address is neither IPv4 nor IPv6" +
+                       "(" + gwStr + ")");
+            return false;
+        }
+        return addRoute(interfaceName, dstStr, 0, gwStr) == 0;
+    }
+
+    /**
+     * Add a host route.
+     * @param interfaceName interface on which the route should be added
+     * @param dst the IP address of the host to which the route is desired,
+     * this should not be null.
+     * @param gw the IP address of the gateway to which the route is desired,
+     * if null, indicates a directly-connected route.
+     * @return {@code true} on success, {@code false} on failure
+     */
+    public static boolean addHostRoute(String interfaceName, InetAddress dst,
+          InetAddress gw) {
+        if (dst == null) {
+            Log.w(TAG, "addHostRoute: dst should not be null");
+            return false;
+        }
+
+        int prefixLength;
+        String dstStr = dst.getHostAddress();
+        String gwStr = (gw != null) ? gw.getHostAddress() : null;
+
+        if (dst instanceof Inet4Address) {
+            prefixLength = 32;
+        } else if (dst instanceof Inet6Address) {
+            prefixLength = 128;
+        } else {
+            Log.w(TAG, "addHostRoute failure: address is neither IPv4 nor IPv6" +
+                       "(" + dst + ")");
+            return false;
+        }
+        return addRoute(interfaceName, dstStr, prefixLength, gwStr) == 0;
     }
 
     public static int v4StringToInt(String str) {
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 66eefb2..c1fa5b4 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -16,12 +16,16 @@
 
 package android.net;
 
+import org.apache.http.HttpHost;
+
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Log;
 
+import java.net.URI;
+
 import junit.framework.Assert;
 
 /**
@@ -120,4 +124,73 @@
         }
     }
 
+    /**
+     * Returns the preferred proxy to be used by clients. This is a wrapper
+     * around {@link android.net.Proxy#getHost()}. Currently no proxy will
+     * be returned for localhost or if the active network is Wi-Fi.
+     *
+     * @param context the context which will be passed to
+     * {@link android.net.Proxy#getHost()}
+     * @param url the target URL for the request
+     * @note Calling this method requires permission
+     * android.permission.ACCESS_NETWORK_STATE
+     * @return The preferred proxy to be used by clients, or null if there
+     * is no proxy.
+     *
+     * {@hide}
+     */
+    static final public HttpHost getPreferredHttpHost(Context context,
+            String url) {
+        if (!isLocalHost(url) && !isNetworkWifi(context)) {
+            final String proxyHost = Proxy.getHost(context);
+            if (proxyHost != null) {
+                return new HttpHost(proxyHost, Proxy.getPort(context), "http");
+            }
+        }
+
+        return null;
+    }
+
+    static final private boolean isLocalHost(String url) {
+        if (url == null) {
+            return false;
+        }
+
+        try {
+            final URI uri = URI.create(url);
+            final String host = uri.getHost();
+            if (host != null) {
+                // TODO: InetAddress.isLoopbackAddress should be used to check
+                // for localhost. However no public factory methods exist which
+                // can be used without triggering DNS lookup if host is not localhost.
+                if (host.equalsIgnoreCase("localhost") ||
+                        host.equals("127.0.0.1") ||
+                        host.equals("[::1]")) {
+                    return true;
+                }
+            }
+        } catch (IllegalArgumentException iex) {
+            // Ignore (URI.create)
+        }
+
+        return false;
+    }
+
+    static final private boolean isNetworkWifi(Context context) {
+        if (context == null) {
+            return false;
+        }
+
+        final ConnectivityManager connectivity = (ConnectivityManager)
+            context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (connectivity != null) {
+            final NetworkInfo info = connectivity.getActiveNetworkInfo();
+            if (info != null &&
+                    info.getType() == ConnectivityManager.TYPE_WIFI) {
+                return true;
+            }
+        }
+
+        return false;
+    }
 };
diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java
index 09f6f4f..74c0de8 100644
--- a/core/java/android/net/http/Headers.java
+++ b/core/java/android/net/http/Headers.java
@@ -262,7 +262,14 @@
             break;
         case HASH_CACHE_CONTROL:
             if (name.equals(CACHE_CONTROL)) {
-                mHeaders[IDX_CACHE_CONTROL] = val;
+                // In case where we receive more than one header, create a ',' separated list.
+                // This should be ok, according to RFC 2616 chapter 4.2
+                if (mHeaders[IDX_CACHE_CONTROL] != null &&
+                    mHeaders[IDX_CACHE_CONTROL].length() > 0) {
+                    mHeaders[IDX_CACHE_CONTROL] += (',' + val);
+                } else {
+                    mHeaders[IDX_CACHE_CONTROL] = val;
+                }
             }
             break;
         case HASH_LAST_MODIFIED:
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index b361dca..d77e9d9 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -205,10 +205,13 @@
                 BasicHttpRequest proxyReq = new BasicHttpRequest
                     ("CONNECT", mHost.toHostString());
 
-                // add all 'proxy' headers from the original request
+                // add all 'proxy' headers from the original request, we also need
+                // to add 'host' header unless we want proxy to answer us with a
+                // 400 Bad Request
                 for (Header h : req.mHttpRequest.getAllHeaders()) {
                     String headerName = h.getName().toLowerCase();
-                    if (headerName.startsWith("proxy") || headerName.equals("keep-alive")) {
+                    if (headerName.startsWith("proxy") || headerName.equals("keep-alive")
+                            || headerName.equals("host")) {
                         proxyReq.addHeader(h);
                     }
                 }
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 44b73c5..bd57b33 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -99,6 +99,7 @@
     public static final int BATTERY_HEALTH_DEAD = 4;
     public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
     public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
+    public static final int BATTERY_HEALTH_COLD = 7;
 
     // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
     // These must be powers of 2.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2e14667..86f9a6b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -94,7 +94,8 @@
     /**
      * Default trace file path and file
      */
-    private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/";
+    private static final String DEFAULT_TRACE_PATH_PREFIX =
+        Environment.getExternalStorageDirectory().getPath() + "/";
     private static final String DEFAULT_TRACE_BODY = "dmtrace";
     private static final String DEFAULT_TRACE_EXTENSION = ".trace";
     private static final String DEFAULT_TRACE_FILE_PATH =
@@ -127,7 +128,7 @@
         public int otherPrivateDirty;
         /** The shared dirty pages used by everything else. */
         public int otherSharedDirty;
-        
+
         public MemoryInfo() {
         }
 
@@ -137,21 +138,21 @@
         public int getTotalPss() {
             return dalvikPss + nativePss + otherPss;
         }
-        
+
         /**
          * Return total private dirty memory usage in kB.
          */
         public int getTotalPrivateDirty() {
             return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
         }
-        
+
         /**
          * Return total shared dirty memory usage in kB.
          */
         public int getTotalSharedDirty() {
             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
         }
-        
+
         public int describeContents() {
             return 0;
         }
@@ -179,7 +180,7 @@
             otherPrivateDirty = source.readInt();
             otherSharedDirty = source.readInt();
         }
-        
+
         public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
             public MemoryInfo createFromParcel(Parcel source) {
                 return new MemoryInfo(source);
@@ -460,7 +461,7 @@
      * Like startMethodTracing(String, int, int), but taking an already-opened
      * FileDescriptor in which the trace is written.  The file name is also
      * supplied simply for logging.  Makes a dup of the file descriptor.
-     * 
+     *
      * Not exposed in the SDK unless we are really comfortable with supporting
      * this and find it would be useful.
      * @hide
@@ -1070,7 +1071,7 @@
      *    static {
      *        // Sets all the fields
      *        Debug.setFieldsOn(MyDebugVars.class);
-     * 
+     *
      *        // Sets only the fields annotated with @Debug.DebugProperty
      *        // Debug.setFieldsOn(MyDebugVars.class, true);
      *    }
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index f842d75..f44cbe4 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -39,6 +39,7 @@
     private CharSequence[] mEntries;
     private CharSequence[] mEntryValues;
     private String mValue;
+    private String mSummary;
     private int mClickedDialogEntryIndex;
     
     public ListPreference(Context context, AttributeSet attrs) {
@@ -49,8 +50,16 @@
         mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries);
         mEntryValues = a.getTextArray(com.android.internal.R.styleable.ListPreference_entryValues);
         a.recycle();
+
+        /* Retrieve the Preference summary attribute since it's private
+         * in the Preference class.
+         */
+        a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.Preference, 0, 0);
+        mSummary = a.getString(com.android.internal.R.styleable.Preference_summary);
+        a.recycle();
     }
-    
+
     public ListPreference(Context context) {
         this(context, null);
     }
@@ -127,6 +136,43 @@
     }
 
     /**
+     * Returns the summary of this ListPreference. If the summary
+     * has a {@linkplain java.lang.String#format String formatting}
+     * marker in it (i.e. "%s" or "%1$s"), then the current entry
+     * value will be substituted in its place.
+     *
+     * @return the summary with appropriate string substitution
+     */
+    @Override
+    public CharSequence getSummary() {
+        final CharSequence entry = getEntry();
+        if (mSummary == null || entry == null) {
+            return super.getSummary();
+        } else {
+            return String.format(mSummary, entry);
+        }
+    }
+
+    /**
+     * Sets the summary for this Preference with a CharSequence.
+     * If the summary has a
+     * {@linkplain java.lang.String#format String formatting}
+     * marker in it (i.e. "%s" or "%1$s"), then the current entry
+     * value will be substituted in its place when it's retrieved.
+     *
+     * @param summary The summary for the preference.
+     */
+    @Override
+    public void setSummary(CharSequence summary) {
+        super.setSummary(summary);
+        if (summary == null && mSummary != null) {
+            mSummary = null;
+        } else if (summary != null && !summary.equals(mSummary)) {
+            mSummary = summary.toString();
+        }
+    }
+
+    /**
      * Sets the value to the given index from the entry values.
      * 
      * @param index The index of the value to set.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5aa22fb..2a13d520 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3620,7 +3620,7 @@
                 while (intent == null && c.moveToNext()) {
                     try {
                         String intentURI = c.getString(c.getColumnIndexOrThrow(INTENT));
-                        intent = Intent.getIntent(intentURI);
+                        intent = Intent.parseUri(intentURI, 0);
                     } catch (java.net.URISyntaxException e) {
                         // The stored URL is bad...  ignore it.
                     } catch (IllegalArgumentException e) {
@@ -3678,7 +3678,7 @@
             ContentValues values = new ContentValues();
             if (title != null) values.put(TITLE, title);
             if (folder != null) values.put(FOLDER, folder);
-            values.put(INTENT, intent.toURI());
+            values.put(INTENT, intent.toUri(0));
             if (shortcut != 0) values.put(SHORTCUT, (int) shortcut);
             values.put(ORDERING, ordering);
             return cr.insert(CONTENT_URI, values);
@@ -3730,7 +3730,7 @@
 
             Intent intent;
             try {
-                intent = Intent.getIntent(intentUri);
+                intent = Intent.parseUri(intentUri, 0);
             } catch (URISyntaxException e) {
                 return "";
             }
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 6d8bd9b..803446f 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -25,6 +25,7 @@
 import android.database.Cursor;
 import android.database.sqlite.SqliteWrapper;
 import android.net.Uri;
+import android.os.Environment;
 import android.telephony.SmsMessage;
 import android.text.TextUtils;
 import android.util.Config;
@@ -561,15 +562,24 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>transactionId (Integer)</em> - The WAP transaction
-             *    ID</li>
+             *   <li><em>transactionId (Integer)</em> - The WAP transaction ID</li>
              *   <li><em>pduType (Integer)</em> - The WAP PDU type</li>
              *   <li><em>header (byte[])</em> - The header of the message</li>
              *   <li><em>data (byte[])</em> - The data payload of the message</li>
+             *   <li><em>contentTypeParameters (HashMap&lt;String,String&gt;)</em>
+             *   - Any parameters associated with the content type
+             *   (decoded from the WSP Content-Type header)</li>
              * </ul>
              *
              * <p>If a BroadcastReceiver encounters an error while processing
              * this intent it should set the result code appropriately.</p>
+             *
+             * <p>The contentTypeParameters extra value is map of content parameters keyed by
+             * their names.</p>
+             *
+             * <p>If any unassigned well-known parameters are encountered, the key of the map will
+             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
+             * a parameter has No-Value the value in the map will be null.</p>
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String WAP_PUSH_RECEIVED_ACTION =
@@ -582,7 +592,7 @@
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String SIM_FULL_ACTION =
-                "android.provider.Telephony.SIM_FULL";
+                    "android.provider.Telephony.SIM_FULL";
 
             /**
              * Broadcast Action: An incoming SMS has been rejected by the
@@ -1525,7 +1535,8 @@
              * which streams the captured image to the uri. Internally we write the media content
              * to this file. It's named '.temp.jpg' so Gallery won't pick it up.
              */
-            public static final String SCRAP_FILE_PATH = "/sdcard/mms/scrapSpace/.temp.jpg";
+            public static final String SCRAP_FILE_PATH =
+                Environment.getExternalStorageDirectory().getPath() + "/mms/scrapSpace/.temp.jpg";
         }
 
         public static final class Intents {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index c877c5c..80d6d30 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -30,6 +30,8 @@
 
 import java.util.HashMap;
 import java.util.Set;
+import android.os.PowerManager;
+
 
 /**
  * TODO: Move this to
@@ -51,6 +53,9 @@
     private final BluetoothService mBluetoothService;
     private final BluetoothAdapter mAdapter;
     private final Context mContext;
+    // The WakeLock is used for bringing up the LCD during a pairing request
+    // from remote device when Android is in Suspend state.
+    private PowerManager.WakeLock mWakeLock;
 
     private static final int EVENT_RESTART_BLUETOOTH = 1;
     private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
@@ -105,6 +110,11 @@
         mContext = context;
         mPasskeyAgentRequestData = new HashMap();
         mAdapter = adapter;
+        //WakeLock instantiation in BluetoothEventLoop class
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
+                | PowerManager.ON_AFTER_RELEASE, TAG);
+        mWakeLock.setReferenceCounted(false);
         initializeNativeDataNative();
     }
 
@@ -398,37 +408,46 @@
             mHandler.sendMessageDelayed(message, 1500);
             return;
         }
-
+        // Acquire wakelock during PIN code request to bring up LCD display
+        mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                         BluetoothDevice.PAIRING_VARIANT_CONSENT);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+        mWakeLock.release();
         return;
     }
 
     private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) {
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
-
+        // Acquire wakelock during PIN code request to bring up LCD display
+        mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                 BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+        mWakeLock.release();
         return;
     }
 
     private void onRequestPasskey(String objectPath, int nativeData) {
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
-
+        // Acquire wakelock during PIN code request to bring up LCD display
+        mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                 BluetoothDevice.PAIRING_VARIANT_PASSKEY);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+        mWakeLock.release();
         return;
     }
 
@@ -461,10 +480,14 @@
                 if (mBluetoothService.attemptAutoPair(address)) return;
            }
         }
+        // Acquire wakelock during PIN code request to bring up LCD display
+        mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+        mWakeLock.release();
         return;
     }
 
@@ -472,12 +495,16 @@
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
 
+        // Acquire wakelock during PIN code request to bring up LCD display
+        mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                         BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        //Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+        mWakeLock.release();
     }
 
     private void onRequestOobData(String objectPath , int nativeData) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
old mode 100644
new mode 100755
index 38ac9b7..4e197cd
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -749,6 +749,9 @@
         if (line == getLineCount() - 1)
             max++;
 
+        if (line != getLineCount() - 1)
+            max = TextUtils.getOffsetBefore(mText, getLineEnd(line));
+
         int best = min;
         float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
 
@@ -893,7 +896,7 @@
         Directions dirs = getLineDirections(line);
 
         if (line != getLineCount() - 1)
-            end--;
+            end = TextUtils.getOffsetBefore(mText, end);
 
         float horiz = getPrimaryHorizontal(offset);
 
@@ -993,7 +996,7 @@
         Directions dirs = getLineDirections(line);
 
         if (line != getLineCount() - 1)
-            end--;
+            end = TextUtils.getOffsetBefore(mText, end);
 
         float horiz = getPrimaryHorizontal(offset);
 
@@ -1564,7 +1567,8 @@
                         h = dir * nextTab(text, start, end, h * dir, tabs);
                     }
 
-                    if (bm != null) {
+                    if (j != there && bm != null) {
+                        if (offset == start + j) return h;
                         workPaint.set(paint);
                         Styled.measureText(paint, workPaint, text,
                                            j, j + 2, null);
@@ -1958,4 +1962,3 @@
                                        new Directions(new short[] { 0, 32767 });
 
 }
-
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
old mode 100644
new mode 100755
index f02ad2a..d0d2482
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -313,7 +313,9 @@
                                                       class);
 
                 if (spanned == null) {
-                    paint.getTextWidths(sub, i, next, widths);
+                    final int actualNum = paint.getTextWidths(sub, i, next, widths);
+                    if (next - i > actualNum)
+                        adjustTextWidths(widths, sub, i, next, actualNum);
                     System.arraycopy(widths, 0, widths,
                                      end - start + (i - start), next - i);
                                      
@@ -321,9 +323,11 @@
                 } else {
                     mWorkPaint.baselineShift = 0;
 
-                    Styled.getTextWidths(paint, mWorkPaint,
-                                         spanned, i, next,
-                                         widths, fm);
+                    final int actualNum = Styled.getTextWidths(paint, mWorkPaint,
+                            spanned, i, next,
+                            widths, fm);
+                    if (next - i > actualNum)
+                        adjustTextWidths(widths, spanned, i, next, actualNum);
                     System.arraycopy(widths, 0, widths,
                                      end - start + (i - start), next - i);
 
@@ -966,6 +970,22 @@
             return low;
     }
 
+    private static void adjustTextWidths(float[] widths, CharSequence text,
+                              int curPos, int nextPos, int actualNum) {
+        try {
+            int dstIndex = nextPos - curPos - 1;
+            for (int srcIndex = actualNum - 1; srcIndex >= 0; srcIndex--) {
+                final char c = text.charAt(dstIndex + curPos);
+                if (c >= 0xD800 && c <= 0xDFFF) {
+                    widths[dstIndex--] = 0.0f;
+                }
+                widths[dstIndex--] = widths[srcIndex];
+            }
+        } catch (IndexOutOfBoundsException e) {
+            Log.e("text", "adjust text widths failed");
+        }
+    }
+
     private int out(CharSequence text, int start, int end,
                       int above, int below, int top, int bottom, int v,
                       float spacingmult, float spacingadd,
diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java
old mode 100644
new mode 100755
index 513b2cd..13cc42c
--- a/core/java/android/text/Styled.java
+++ b/core/java/android/text/Styled.java
@@ -203,9 +203,10 @@
 			}
 		}
 	
+        int result;
         if (replacement == null) {
             workPaint.getFontMetricsInt(fmi);
-            workPaint.getTextWidths(text, start, end, widths);
+            result = workPaint.getTextWidths(text, start, end, widths);
         } else {
             int wid = replacement.getSize(workPaint, text, start, end, fmi);
 
@@ -214,8 +215,9 @@
                 for (int i = start + 1; i < end; i++)
                     widths[i - start] = 0;
             }
+            result = end - start;
         }
-        return end - start;
+        return result;
     }
 
     /**
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 4e2c3c3..a95dad7 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -502,7 +502,7 @@
                 }
             }
         } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
-            count = duration / DAY_IN_MILLIS;
+            count = getNumberOfDaysPassed(time, now);
             if (past) {
                 if (abbrevRelative) {
                     resId = com.android.internal.R.plurals.abbrev_num_days_ago;
@@ -527,6 +527,24 @@
     }
     
     /**
+     * Returns the number of days passed between two dates.
+     *
+     * @param date1 first date
+     * @param date2 second date
+     * @return number of days passed between to dates.
+     */
+    private synchronized static long getNumberOfDaysPassed(long date1, long date2) {
+        if (sThenTime == null) {
+            sThenTime = new Time();
+        }
+        sThenTime.set(date1);
+        int day1 = Time.getJulianDay(date1, sThenTime.gmtoff);
+        sThenTime.set(date2);
+        int day2 = Time.getJulianDay(date2, sThenTime.gmtoff);
+        return Math.abs(day2 - day1);
+    }
+
+    /**
      * Return string describing the elapsed time since startTime formatted like
      * "[relative time/date], [time]".
      * <p>
@@ -1595,40 +1613,45 @@
     public static CharSequence getRelativeTimeSpanString(Context c, long millis,
             boolean withPreposition) {
 
+        String result;
         long now = System.currentTimeMillis();
         long span = now - millis;
 
-        if (sNowTime == null) {
-            sNowTime = new Time();
-            sThenTime = new Time();
-        }
+        synchronized (DateUtils.class) {
+            if (sNowTime == null) {
+                sNowTime = new Time();
+            }
 
-        sNowTime.set(now);
-        sThenTime.set(millis);
+            if (sThenTime == null) {
+                sThenTime = new Time();
+            }
 
-        String result;
-        int prepositionId;
-        if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) {
-            // Same day
-            int flags = FORMAT_SHOW_TIME;
-            result = formatDateRange(c, millis, millis, flags);
-            prepositionId = R.string.preposition_for_time;
-        } else if (sNowTime.year != sThenTime.year) {
-            // Different years
-            int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE;
-            result = formatDateRange(c, millis, millis, flags);
+            sNowTime.set(now);
+            sThenTime.set(millis);
 
-            // This is a date (like "10/31/2008" so use the date preposition)
-            prepositionId = R.string.preposition_for_date;
-        } else {
-            // Default
-            int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
-            result = formatDateRange(c, millis, millis, flags);
-            prepositionId = R.string.preposition_for_date;
-        }
-        if (withPreposition) {
-            Resources res = c.getResources();
-            result = res.getString(prepositionId, result);
+            int prepositionId;
+            if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) {
+                // Same day
+                int flags = FORMAT_SHOW_TIME;
+                result = formatDateRange(c, millis, millis, flags);
+                prepositionId = R.string.preposition_for_time;
+            } else if (sNowTime.year != sThenTime.year) {
+                // Different years
+                int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE;
+                result = formatDateRange(c, millis, millis, flags);
+
+                // This is a date (like "10/31/2008" so use the date preposition)
+                prepositionId = R.string.preposition_for_date;
+            } else {
+                // Default
+                int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
+                result = formatDateRange(c, millis, millis, flags);
+                prepositionId = R.string.preposition_for_date;
+            }
+            if (withPreposition) {
+                Resources res = c.getResources();
+                result = res.getString(prepositionId, result);
+            }
         }
         return result;
     }
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 8eae111..c05a8fe 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -32,7 +32,7 @@
     private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000";
     private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z";
     private static final String Y_M_D = "%Y-%m-%d";
-    
+
     public static final String TIMEZONE_UTC = "UTC";
 
     /**
@@ -170,11 +170,11 @@
     public Time() {
         this(TimeZone.getDefault().getID());
     }
-    
+
     /**
      * A copy constructor.  Construct a Time object by copying the given
      * Time object.  No normalization occurs.
-     * 
+     *
      * @param other
      */
     public Time(Time other) {
@@ -185,17 +185,17 @@
      * Ensures the values in each field are in range. For example if the
      * current value of this calendar is March 32, normalize() will convert it
      * to April 1. It also fills in weekDay, yearDay, isDst and gmtoff.
-     * 
+     *
      * <p>
      * If "ignoreDst" is true, then this method sets the "isDst" field to -1
      * (the "unknown" value) before normalizing.  It then computes the
      * correct value for "isDst".
-     * 
+     *
      * <p>
      * See {@link #toMillis(boolean)} for more information about when to
      * use <tt>true</tt> or <tt>false</tt> for "ignoreDst".
-     * 
-     * @return the UTC milliseconds since the epoch 
+     *
+     * @return the UTC milliseconds since the epoch
      */
     native public long normalize(boolean ignoreDst);
 
@@ -379,13 +379,13 @@
      * Parses a date-time string in either the RFC 2445 format or an abbreviated
      * format that does not include the "time" field.  For example, all of the
      * following strings are valid:
-     * 
+     *
      * <ul>
      *   <li>"20081013T160000Z"</li>
      *   <li>"20081013T160000"</li>
      *   <li>"20081013"</li>
      * </ul>
-     * 
+     *
      * Returns whether or not the time is in UTC (ends with Z).  If the string
      * ends with "Z" then the timezone is set to UTC.  If the date-time string
      * included only a date and no time field, then the <code>allDay</code>
@@ -396,10 +396,10 @@
      * <code>yearDay</code>, and <code>gmtoff</code> are always set to zero,
      * and the field <code>isDst</code> is set to -1 (unknown).  To set those
      * fields, call {@link #normalize(boolean)} after parsing.
-     * 
+     *
      * To parse a date-time string and convert it to UTC milliseconds, do
      * something like this:
-     * 
+     *
      * <pre>
      *   Time time = new Time();
      *   String date = "20081013T160000Z";
@@ -428,25 +428,25 @@
      * Parse a time in RFC 3339 format.  This method also parses simple dates
      * (that is, strings that contain no time or time offset).  For example,
      * all of the following strings are valid:
-     * 
+     *
      * <ul>
      *   <li>"2008-10-13T16:00:00.000Z"</li>
      *   <li>"2008-10-13T16:00:00.000+07:00"</li>
      *   <li>"2008-10-13T16:00:00.000-07:00"</li>
      *   <li>"2008-10-13"</li>
      * </ul>
-     * 
+     *
      * <p>
      * If the string contains a time and time offset, then the time offset will
      * be used to convert the time value to UTC.
      * </p>
-     * 
+     *
      * <p>
      * If the given string contains just a date (with no time field), then
      * the {@link #allDay} field is set to true and the {@link #hour},
      * {@link #minute}, and  {@link #second} fields are set to zero.
      * </p>
-     * 
+     *
      * <p>
      * Returns true if the resulting time value is in UTC time.
      * </p>
@@ -462,7 +462,7 @@
          }
          return false;
      }
-     
+
      native private boolean nativeParse3339(String s);
 
     /**
@@ -484,13 +484,13 @@
      * <em>not</em> change any of the fields in this Time object.  If you want
      * to normalize the fields in this Time object and also get the milliseconds
      * then use {@link #normalize(boolean)}.
-     * 
+     *
      * <p>
      * If "ignoreDst" is false, then this method uses the current setting of the
      * "isDst" field and will adjust the returned time if the "isDst" field is
      * wrong for the given time.  See the sample code below for an example of
      * this.
-     * 
+     *
      * <p>
      * If "ignoreDst" is true, then this method ignores the current setting of
      * the "isDst" field in this Time object and will instead figure out the
@@ -499,27 +499,27 @@
      * correct value of the "isDst" field is when the time is inherently
      * ambiguous because it falls in the hour that is repeated when switching
      * from Daylight-Saving Time to Standard Time.
-     * 
+     *
      * <p>
      * Here is an example where <tt>toMillis(true)</tt> adjusts the time,
      * assuming that DST changes at 2am on Sunday, Nov 4, 2007.
-     * 
+     *
      * <pre>
      * Time time = new Time();
-     * time.set(2007, 10, 4);  // set the date to Nov 4, 2007, 12am
+     * time.set(4, 10, 2007);  // set the date to Nov 4, 2007, 12am
      * time.normalize();       // this sets isDst = 1
      * time.monthDay += 1;     // changes the date to Nov 5, 2007, 12am
      * millis = time.toMillis(false);   // millis is Nov 4, 2007, 11pm
      * millis = time.toMillis(true);    // millis is Nov 5, 2007, 12am
      * </pre>
-     * 
+     *
      * <p>
      * To avoid this problem, use <tt>toMillis(true)</tt>
      * after adding or subtracting days or explicitly setting the "monthDay"
      * field.  On the other hand, if you are adding
      * or subtracting hours or minutes, then you should use
      * <tt>toMillis(false)</tt>.
-     * 
+     *
      * <p>
      * You should also use <tt>toMillis(false)</tt> if you want
      * to read back the same milliseconds that you set with {@link #set(long)}
@@ -531,14 +531,14 @@
      * Sets the fields in this Time object given the UTC milliseconds.  After
      * this method returns, all the fields are normalized.
      * This also sets the "isDst" field to the correct value.
-     * 
+     *
      * @param millis the time in UTC milliseconds since the epoch.
      */
     native public void set(long millis);
 
     /**
      * Format according to RFC 2445 DATETIME type.
-     * 
+     *
      * <p>
      * The same as format("%Y%m%dT%H%M%S").
      */
@@ -584,7 +584,7 @@
      * Sets the date from the given fields.  Also sets allDay to true.
      * Sets weekDay, yearDay and gmtoff to 0, and isDst to -1.
      * Call {@link #normalize(boolean)} if you need those.
-     * 
+     *
      * @param monthDay the day of the month (in the range [1,31])
      * @param month the zero-based month number (in the range [0,11])
      * @param year the year
@@ -606,7 +606,7 @@
     /**
      * Returns true if the time represented by this Time object occurs before
      * the given time.
-     * 
+     *
      * @param that a given Time object to compare against
      * @return true if this time is less than the given time
      */
@@ -618,7 +618,7 @@
     /**
      * Returns true if the time represented by this Time object occurs after
      * the given time.
-     * 
+     *
      * @param that a given Time object to compare against
      * @return true if this time is greater than the given time
      */
@@ -632,12 +632,12 @@
      * closest Thursday yearDay.
      */
     private static final int[] sThursdayOffset = { -3, 3, 2, 1, 0, -1, -2 };
-        
+
     /**
      * Computes the week number according to ISO 8601.  The current Time
      * object must already be normalized because this method uses the
      * yearDay and weekDay fields.
-     * 
+     *
      * <p>
      * In IS0 8601, weeks start on Monday.
      * The first week of the year (week 1) is defined by ISO 8601 as the
@@ -645,12 +645,12 @@
      * Or equivalently, the week containing January 4.  Or equivalently,
      * the week with the year's first Thursday in it.
      * </p>
-     * 
+     *
      * <p>
      * The week number can be calculated by counting Thursdays.  Week N
      * contains the Nth Thursday of the year.
      * </p>
-     *   
+     *
      * @return the ISO week number.
      */
     public int getWeekNumber() {
@@ -661,7 +661,7 @@
         if (closestThursday >= 0 && closestThursday <= 364) {
             return closestThursday / 7 + 1;
         }
-        
+
         // The week crosses a year boundary.
         Time temp = new Time(this);
         temp.monthDay += sThursdayOffset[weekDay];
@@ -670,7 +670,7 @@
     }
 
     /**
-     * Return a string in the RFC 3339 format. 
+     * Return a string in the RFC 3339 format.
      * <p>
      * If allDay is true, expresses the time as Y-M-D</p>
      * <p>
@@ -691,13 +691,13 @@
             int offset = (int)Math.abs(gmtoff);
             int minutes = (offset % 3600) / 60;
             int hours = offset / 3600;
-            
+
             return String.format("%s%s%02d:%02d", base, sign, hours, minutes);
         }
     }
-    
+
     /**
-     * Returns true if the day of the given time is the epoch on the Julian Calendar 
+     * Returns true if the day of the given time is the epoch on the Julian Calendar
      * (January 1, 1970 on the Gregorian calendar).
      *
      * @param time the time to test
@@ -707,7 +707,7 @@
         long millis = time.toMillis(true);
         return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY;
     }
-    
+
     /**
      * Computes the Julian day number, given the UTC milliseconds
      * and the offset (in seconds) from UTC.  The Julian day for a given
@@ -716,10 +716,10 @@
      * what timezone is being used.  The Julian day is useful for testing
      * if two events occur on the same day and for determining the relative
      * time of an event from the present ("yesterday", "3 days ago", etc.).
-     * 
+     *
      * <p>
      * Use {@link #toMillis(boolean)} to get the milliseconds.
-     * 
+     *
      * @param millis the time in UTC milliseconds
      * @param gmtoff the offset from UTC in seconds
      * @return the Julian day
@@ -729,7 +729,7 @@
         long julianDay = (millis + offsetMillis) / DateUtils.DAY_IN_MILLIS;
         return (int) julianDay + EPOCH_JULIAN_DAY;
     }
-    
+
     /**
      * <p>Sets the time from the given Julian day number, which must be based on
      * the same timezone that is set in this Time object.  The "gmtoff" field
@@ -738,7 +738,7 @@
      * After this method returns all the fields will be normalized and the time
      * will be set to 12am at the beginning of the given Julian day.
      * </p>
-     * 
+     *
      * <p>
      * The only exception to this is if 12am does not exist for that day because
      * of daylight saving time.  For example, Cairo, Eqypt moves time ahead one
@@ -746,7 +746,7 @@
      * also change daylight saving time at 12am.  In those cases, the time
      * will be set to 1am.
      * </p>
-     * 
+     *
      * @param julianDay the Julian day in the timezone for this Time object
      * @return the UTC milliseconds for the beginning of the Julian day
      */
@@ -756,13 +756,13 @@
         // the day.
         long millis = (julianDay - EPOCH_JULIAN_DAY) * DateUtils.DAY_IN_MILLIS;
         set(millis);
-        
+
         // Figure out how close we are to the requested Julian day.
         // We can't be off by more than a day.
         int approximateDay = getJulianDay(millis, gmtoff);
         int diff = julianDay - approximateDay;
         monthDay += diff;
-        
+
         // Set the time to 12am and re-normalize.
         hour = 0;
         minute = 0;
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 15fb839..8ad9a62 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -266,7 +266,7 @@
 
 
     /**
-     * Do the "beams" w.r.t the given direcition's axos of rect1 and rect2 overlap?
+     * Do the "beams" w.r.t the given direcition's axis of rect1 and rect2 overlap?
      * @param direction the direction (up, down, left, right)
      * @param rect1 The first rectangle
      * @param rect2 The second rectangle
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index acda3e1..54cedfb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3944,6 +3944,7 @@
                 imm.focusOut(this);
             }
             removeLongPressCallback();
+            removeTapCallback();
             onFocusLost();
         } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
             imm.focusIn(this);
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index ca9ad53..c1ac180 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -369,10 +369,13 @@
             sMimeTypeMap.loadEntry("application/x-xfig", "fig");
             sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml");
             sMimeTypeMap.loadEntry("audio/3gpp", "3gpp");
+            sMimeTypeMap.loadEntry("audio/amr", "amr");
             sMimeTypeMap.loadEntry("audio/basic", "snd");
             sMimeTypeMap.loadEntry("audio/midi", "mid");
             sMimeTypeMap.loadEntry("audio/midi", "midi");
             sMimeTypeMap.loadEntry("audio/midi", "kar");
+            sMimeTypeMap.loadEntry("audio/midi", "xmf");
+            sMimeTypeMap.loadEntry("audio/mobile-xmf", "mxmf");
             sMimeTypeMap.loadEntry("audio/mpeg", "mpga");
             sMimeTypeMap.loadEntry("audio/mpeg", "mpega");
             sMimeTypeMap.loadEntry("audio/mpeg", "mp2");
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9098639..7251764 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -313,6 +313,10 @@
     // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
     private boolean mAutoRedraw;
 
+    // Reference to the AlertDialog displayed by InvokeListBox.
+    // It's used to dismiss the dialog in destroy if not done before.
+    private AlertDialog mListBoxDialog = null;
+
     static final String LOGTAG = "webview";
 
     private static class ExtendedZoomControls extends FrameLayout {
@@ -1301,6 +1305,10 @@
      */
     public void destroy() {
         clearHelpers();
+        if (mListBoxDialog != null) {
+            mListBoxDialog.dismiss();
+            mListBoxDialog = null;
+        }
         if (mWebViewCore != null) {
             // Set the handlers to null before destroying WebViewCore so no
             // more messages will be posted.
@@ -4170,6 +4178,16 @@
             }
         }
 
+        if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
+            pageUp(false);
+            return true;
+        }
+
+        if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
+            pageDown(false);
+            return true;
+        }
+
         if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
                 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
             switchOutDrawHistory();
@@ -7537,7 +7555,7 @@
                                 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
                 }});
             }
-            final AlertDialog dialog = b.create();
+            mListBoxDialog = b.create();
             listView.setAdapter(adapter);
             listView.setFocusableInTouchMode(true);
             // There is a bug (1250103) where the checks in a ListView with
@@ -7559,7 +7577,8 @@
                             int position, long id) {
                         mWebViewCore.sendMessage(
                                 EventHub.SINGLE_LISTBOX_CHOICE, (int)id, 0);
-                        dialog.dismiss();
+                        mListBoxDialog.dismiss();
+                        mListBoxDialog = null;
                     }
                 });
                 if (mSelection != -1) {
@@ -7571,13 +7590,14 @@
                     adapter.registerDataSetObserver(observer);
                 }
             }
-            dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+            mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                 public void onCancel(DialogInterface dialog) {
                     mWebViewCore.sendMessage(
                                 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
+                    mListBoxDialog = null;
                 }
             });
-            dialog.show();
+            mListBoxDialog.show();
         }
     }
 
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 32e5504..03ada94 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -24,6 +24,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Comparator;
 import java.util.Collections;
@@ -83,7 +84,7 @@
      */
     private boolean mNotifyOnChange = true;
 
-    private Context mContext;    
+    private Context mContext;
 
     private ArrayList<T> mOriginalValues;
     private ArrayFilter mFilter;
@@ -181,6 +182,44 @@
     }
 
     /**
+     * Adds the specified Collection at the end of the array.
+     *
+     * @param collection The Collection to add at the end of the array.
+     */
+    public void addAll(Collection<? extends T> collection) {
+        if (mOriginalValues != null) {
+            synchronized (mLock) {
+                mOriginalValues.addAll(collection);
+                if (mNotifyOnChange) notifyDataSetChanged();
+            }
+        } else {
+            mObjects.addAll(collection);
+            if (mNotifyOnChange) notifyDataSetChanged();
+        }
+    }
+
+    /**
+     * Adds the specified items at the end of the array.
+     *
+     * @param items The items to add at the end of the array.
+     */
+    public void addAll(T ... items) {
+        if (mOriginalValues != null) {
+            synchronized (mLock) {
+                for (T item : items) {
+                    mOriginalValues.add(item);
+                }
+                if (mNotifyOnChange) notifyDataSetChanged();
+            }
+        } else {
+            for (T item : items) {
+                mObjects.add(item);
+            }
+            if (mNotifyOnChange) notifyDataSetChanged();
+        }
+    }
+
+    /**
      * Inserts the specified object at the specified index in the array.
      *
      * @param object The object to insert into the array.
@@ -236,7 +275,7 @@
      */
     public void sort(Comparator<? super T> comparator) {
         Collections.sort(mObjects, comparator);
-        if (mNotifyOnChange) notifyDataSetChanged();        
+        if (mNotifyOnChange) notifyDataSetChanged();
     }
 
     /**
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 54c4b36..aa68a74 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -154,6 +154,11 @@
         int textColorNormal = textColor.getDefaultColor();
         mPaint.setColor(textColorNormal);
         mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+        // to show mOverlayDrawable properly
+        if (mList.getWidth() > 0 && mList.getHeight() > 0) {
+            onSizeChanged(mList.getWidth(), mList.getHeight(), 0, 0);
+        }
         
         mState = STATE_NONE;
     }
diff --git a/core/java/android/widget/NumberPickerButton.java b/core/java/android/widget/NumberPickerButton.java
index 1c8579c..292b668 100644
--- a/core/java/android/widget/NumberPickerButton.java
+++ b/core/java/android/widget/NumberPickerButton.java
@@ -85,4 +85,12 @@
             mNumberPicker.cancelDecrement();
         }
     }
+
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (!hasWindowFocus) {
+            cancelLongpress();
+        }
+    }
+
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d719783..61020a5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -976,6 +976,22 @@
         setTypeface(tf, styleIndex);
     }
 
+    @Override
+    public void setEnabled(boolean enabled) {
+        if (enabled == isEnabled()) {
+            return;
+        }
+
+        if (!enabled) {
+            // Hide the soft input if the currently active TextView is disabled
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null && imm.isActive(this)) {
+                imm.hideSoftInputFromWindow(getWindowToken(), 0);
+            }
+        }
+        super.setEnabled(enabled);
+    }
+
     /**
      * Sets the typeface and style in which the text should be displayed,
      * and turns on the fake bold and italic bits in the Paint if the
@@ -4562,7 +4578,7 @@
     }
     
     @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-        if (onCheckIsTextEditor()) {
+        if (onCheckIsTextEditor() && isEnabled()) {
             if (mInputMethodState == null) {
                 mInputMethodState = new InputMethodState();
             }
@@ -4636,6 +4652,9 @@
                     partialStartOffset = 0;
                     partialEndOffset = N;
                 } else {
+                    // Now use the delta to determine the actual amount of text
+                    // we need.
+                    partialEndOffset += delta;
                     // Adjust offsets to ensure we contain full spans.
                     if (content instanceof Spanned) {
                         Spanned spanned = (Spanned)content;
@@ -4651,10 +4670,8 @@
                         }
                     }
                     outText.partialStartOffset = partialStartOffset;
-                    outText.partialEndOffset = partialEndOffset;
-                    // Now use the delta to determine the actual amount of text
-                    // we need.
-                    partialEndOffset += delta;
+                    outText.partialEndOffset = partialEndOffset - delta;
+
                     if (partialStartOffset > N) {
                         partialStartOffset = N;
                     } else if (partialStartOffset < 0) {
@@ -4718,6 +4735,10 @@
                                     + ": " + ims.mTmpExtracted.text);
                             imm.updateExtractedText(this, req.token,
                                     mInputMethodState.mTmpExtracted);
+                            ims.mChangedStart = EXTRACT_UNKNOWN;
+                            ims.mChangedEnd = EXTRACT_UNKNOWN;
+                            ims.mChangedDelta = 0;
+                            ims.mContentChanged = false;
                             return true;
                         }
                     }
@@ -6316,8 +6337,8 @@
                 ims.mChangedStart = start;
                 ims.mChangedEnd = start+before;
             } else {
-                if (ims.mChangedStart > start) ims.mChangedStart = start;
-                if (ims.mChangedEnd < (start+before)) ims.mChangedEnd = start+before;
+                ims.mChangedStart = Math.min(ims.mChangedStart, start);
+                ims.mChangedEnd = Math.max(ims.mChangedEnd, start + before - ims.mChangedDelta);
             }
             ims.mChangedDelta += after-before;
         }
@@ -6816,7 +6837,8 @@
             return superResult;
         }
 
-        if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) {
+        if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
+                && mText instanceof Spannable && mLayout != null) {
             if (mInsertionPointCursorController != null) {
                 mInsertionPointCursorController.onTouchEvent(event);
             }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 81ca912..fefdcea 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -434,6 +434,7 @@
                 View titleTemplate = mWindow.findViewById(R.id.title_template);
                 titleTemplate.setVisibility(View.GONE);
                 mIconView.setVisibility(View.GONE);
+                topPanel.setVisibility(View.GONE);
                 hasTitle = false;
             }
         }
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index b7255bb..cd1b569 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -71,7 +71,8 @@
     private boolean mActionDone;
     private Context mContext;
     private PowerManager mPowerManager;
-    private PowerManager.WakeLock mWakeLock;
+    private PowerManager.WakeLock mCpuWakeLock;
+    private PowerManager.WakeLock mScreenWakeLock;
     private Handler mHandler;
     
     private ShutdownThread() {
@@ -138,7 +139,7 @@
     private static void beginShutdownSequence(Context context) {
         synchronized (sIsStartedGuard) {
             if (sIsStarted) {
-                Log.d(TAG, "Request to shutdown already running, returning.");
+                Log.d(TAG, "Shutdown sequence already running, returning.");
                 return;
             }
             sIsStarted = true;
@@ -159,20 +160,36 @@
 
         pd.show();
 
-        // start the thread that initiates shutdown
         sInstance.mContext = context;
         sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        sInstance.mWakeLock = null;
+
+        // make sure we never fall asleep again
+        sInstance.mCpuWakeLock = null;
+        try {
+            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
+                    PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
+            sInstance.mCpuWakeLock.setReferenceCounted(false);
+            sInstance.mCpuWakeLock.acquire();
+        } catch (SecurityException e) {
+            Log.w(TAG, "No permission to acquire wake lock", e);
+            sInstance.mCpuWakeLock = null;
+        }
+
+        // also make sure the screen stays on for better user experience
+        sInstance.mScreenWakeLock = null;
         if (sInstance.mPowerManager.isScreenOn()) {
             try {
-                sInstance.mWakeLock = sInstance.mPowerManager.newWakeLock(
-                        PowerManager.FULL_WAKE_LOCK, "Shutdown");
-                sInstance.mWakeLock.acquire();
+                sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
+                        PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
+                sInstance.mScreenWakeLock.setReferenceCounted(false);
+                sInstance.mScreenWakeLock.acquire();
             } catch (SecurityException e) {
                 Log.w(TAG, "No permission to acquire wake lock", e);
-                sInstance.mWakeLock = null;
+                sInstance.mScreenWakeLock = null;
             }
         }
+
+        // start the thread that initiates shutdown
         sInstance.mHandler = new Handler() {
         };
         sInstance.start();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bc6d6d2..1f42fbd 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -975,7 +975,7 @@
     
     private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
         
-        byte[] buffer = new byte[4096];
+        byte[] buffer = new byte[8192];
         int len;
         
         try {
@@ -1022,9 +1022,11 @@
                 for (endIndex=startIndex; 
                         endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; 
                         endIndex++);
-                // Don't go over the end of the buffer
-                if (endIndex < len) {
-                    endIndex++; // endIndex is an exclusive upper bound.
+                endIndex++; // endIndex is an exclusive upper bound.
+                // Don't go over the end of the buffer, Process.parseProcLine might
+                // write to wlBuffer[endIndex]
+                if (endIndex >= (len - 1) ) {
+                    return m;
                 }
 
                 String[] nameStringArray = mProcWakelocksName;
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index a3efbc8..ea278a6 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -96,7 +96,8 @@
             pending = true;
             snapshotWriter.execute(new Runnable() {
                 public void run() {
-                    String dir = "/sdcard/snapshots";
+                    String dir =
+                        Environment.getExternalStorageDirectory().getPath() + "/snapshots";
                     if (!dirMade) {
                         new File(dir).mkdirs();
                         if (new File(dir).isDirectory()) {
diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java
index 21f0c93..8edfe52 100644
--- a/core/java/com/google/android/mms/pdu/PduParser.java
+++ b/core/java/com/google/android/mms/pdu/PduParser.java
@@ -163,6 +163,13 @@
                     // or "application/vnd.wap.multipart.related"
                     // or "application/vnd.wap.multipart.alternative"
                     return retrieveConf;
+                } else if (ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) {
+                    // "application/vnd.wap.multipart.alternative"
+                    // should take only the first part.
+                    PduPart firstPart = mBody.getPart(0);
+                    mBody.removeAll();
+                    mBody.addPart(0, firstPart);
+                    return retrieveConf;
                 }
                 return null;
             case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index feb0dad..6575b9a 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -25,9 +25,8 @@
 extern "C" {
 int ifc_enable(const char *ifname);
 int ifc_disable(const char *ifname);
-int ifc_add_host_route(const char *ifname, uint32_t addr);
+int ifc_add_route(const char *ifname, const char *destStr, uint32_t prefixLen, const char *gwStr);
 int ifc_remove_host_routes(const char *ifname);
-int ifc_set_default_route(const char *ifname, uint32_t gateway);
 int ifc_get_default_route(const char *ifname);
 int ifc_remove_default_route(const char *ifname);
 int ifc_reset_connections(const char *ifname);
@@ -87,13 +86,23 @@
     return (jint)result;
 }
 
-static jint android_net_utils_addHostRoute(JNIEnv* env, jobject clazz, jstring ifname, jint addr)
+static jint android_net_utils_addRoute(JNIEnv* env, jobject clazz, jstring ifname,
+          jstring dst, jint prefixLength, jstring gw)
 {
     int result;
 
     const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    result = ::ifc_add_host_route(nameStr, addr);
+    const char *dstStr = env->GetStringUTFChars(dst, NULL);
+    const char *gwStr = NULL;
+    if (gw != NULL) {
+        gwStr = env->GetStringUTFChars(gw, NULL);
+    }
+    result = ::ifc_add_route(nameStr, dstStr, prefixLength, gwStr);
     env->ReleaseStringUTFChars(ifname, nameStr);
+    env->ReleaseStringUTFChars(dst, dstStr);
+    if (gw != NULL) {
+        env->ReleaseStringUTFChars(gw, gwStr);
+    }
     return (jint)result;
 }
 
@@ -107,16 +116,6 @@
     return (jint)result;
 }
 
-static jint android_net_utils_setDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname, jint gateway)
-{
-    int result;
-
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    result = ::ifc_set_default_route(nameStr, gateway);
-    env->ReleaseStringUTFChars(ifname, nameStr);
-    return (jint)result;
-}
-
 static jint android_net_utils_getDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
 {
     int result;
@@ -222,9 +221,9 @@
 
     { "enableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_enableInterface },
     { "disableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_disableInterface },
-    { "addHostRoute", "(Ljava/lang/String;I)I",  (void *)android_net_utils_addHostRoute },
+    { "addRoute", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)I",
+       (void *)android_net_utils_addRoute },
     { "removeHostRoutes", "(Ljava/lang/String;)I",  (void *)android_net_utils_removeHostRoutes },
-    { "setDefaultRoute", "(Ljava/lang/String;I)I",  (void *)android_net_utils_setDefaultRoute },
     { "getDefaultRoute", "(Ljava/lang/String;)I",  (void *)android_net_utils_getDefaultRoute },
     { "removeDefaultRoute", "(Ljava/lang/String;)I",  (void *)android_net_utils_removeDefaultRoute },
     { "resetConnections", "(Ljava/lang/String;)I",  (void *)android_net_utils_resetConnections },
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 7696bb3..53028c3 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -17,7 +17,7 @@
 
 #define LOG_TAG "AndroidUnicode"
 
-#include <jni.h>
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include "utils/misc.h"
 #include "utils/Log.h"
@@ -25,14 +25,6 @@
 
 namespace android {
     
-static void jniThrowException(JNIEnv* env, const char* exc, const char* msg = NULL)
-{
-    jclass excClazz = env->FindClass(exc);
-    LOG_ASSERT(excClazz, "Unable to find class %s", exc);
-
-    env->ThrowNew(excClazz, msg);
-}
-
 static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray, 
                     jbyteArray infoArray, int n, jboolean haveInfo)
 {
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 5d8d419..6b90541 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -17,7 +17,7 @@
 
 #define LOG_TAG "AndroidUnicode"
 
-#include <jni.h>
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include "utils/misc.h"
 #include "utils/Log.h"
@@ -50,14 +50,6 @@
 
 namespace android {
     
-static void jniThrowException(JNIEnv* env, const char* exc, const char* msg = NULL)
-{
-    jclass excClazz = env->FindClass(exc);
-    LOG_ASSERT(excClazz, "Unable to find class %s", exc);
-
-    env->ThrowNew(excClazz, msg);
-}
-
 static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, jbyteArray destArray, int count)
 {
     jchar* src = env->GetCharArrayElements(srcArray, NULL);
diff --git a/core/res/res/layout/always_use_checkbox.xml b/core/res/res/layout/always_use_checkbox.xml
index baa4bee..a955352 100644
--- a/core/res/res/layout/always_use_checkbox.xml
+++ b/core/res/res/layout/always_use_checkbox.xml
@@ -26,14 +26,14 @@
     
     <CheckBox
         android:id="@+id/alwaysUse"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:focusable="true"
         android:clickable="true" />
     
     <TextView 
         android:id="@+id/clearDefaultHint"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:paddingLeft="36dip"
diff --git a/core/res/res/raw-ar/loaderror.html b/core/res/res/raw-ar/loaderror.html
index edcd63a..aa9805c 100644
--- a/core/res/res/raw-ar/loaderror.html
+++ b/core/res/res/raw-ar/loaderror.html
@@ -2,7 +2,7 @@
     <head>
         <title>صفحة الويب غير متوفرة</title>
         <style type="text/css">
-            body { margin-top: 0px; padding-top: 0px; }
+            body { margin-top: 0px; padding-top: 0px; direction: rtl; }
             h2   { margin-top: 5px; padding-top: 0px; }
         </style>
 
diff --git a/core/res/res/raw-ar/nodomain.html b/core/res/res/raw-ar/nodomain.html
index bc070f6..2e5849f 100644
--- a/core/res/res/raw-ar/nodomain.html
+++ b/core/res/res/raw-ar/nodomain.html
@@ -2,7 +2,7 @@
     <head>
         <title>صفحة الويب غير متوفرة</title>
         <style type="text/css">
-            body { margin-top: 0px; padding-top: 0px; }
+            body { margin-top: 0px; padding-top: 0px; direction: rtl; }
             h2   { margin-top: 5px; padding-top: 0px; }
         </style>
 
diff --git a/core/res/res/raw-iw/loaderror.html b/core/res/res/raw-iw/loaderror.html
index 8155432..8d5a53f 100644
--- a/core/res/res/raw-iw/loaderror.html
+++ b/core/res/res/raw-iw/loaderror.html
@@ -2,7 +2,7 @@
     <head>
         <title>דף אינטרנט לא זמין</title>
         <style type="text/css">
-            body { margin-top: 0px; padding-top: 0px; }
+            body { margin-top: 0px; padding-top: 0px; direction: rtl; }
             h2   { margin-top: 5px; padding-top: 0px; }
         </style>
 
diff --git a/core/res/res/raw-iw/nodomain.html b/core/res/res/raw-iw/nodomain.html
index f7b9f42..0dcd7f8 100644
--- a/core/res/res/raw-iw/nodomain.html
+++ b/core/res/res/raw-iw/nodomain.html
@@ -2,7 +2,7 @@
     <head>
         <title>דף אינטרנט לא זמין</title>
         <style type="text/css">
-            body { margin-top: 0px; padding-top: 0px; }
+            body { margin-top: 0px; padding-top: 0px; direction: rtl; }
             h2   { margin-top: 5px; padding-top: 0px; }
         </style>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 99fc5c2..f3f7892 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -272,6 +272,21 @@
     <!-- Default LED off time for notification LED in milliseconds. -->
     <integer name="config_defaultNotificationLedOff">2000</integer>
 
+    <!-- Default value for led color when battery is low on charge -->
+    <integer name="config_notificationsBatteryLowARGB">0xFFFF0000</integer>
+
+    <!-- Default value for led color when battery is medium charged -->
+    <integer name="config_notificationsBatteryMediumARGB">0xFFFFFF00</integer>
+
+    <!-- Default value for led color when battery is fully charged -->
+    <integer name="config_notificationsBatteryFullARGB">0xFF00FF00</integer>
+
+    <!-- Default value for LED on time when the battery is low on charge in miliseconds -->
+    <integer name="config_notificationsBatteryLedOn">125</integer>
+
+    <!-- Default value for LED off time when the battery is low on charge in miliseconds -->
+    <integer name="config_notificationsBatteryLedOff">2875</integer>
+
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
 
diff --git a/core/tests/coretests/src/android/preference/ListPreferenceTest.java b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
new file mode 100644
index 0000000..41f8e03
--- /dev/null
+++ b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.preference;
+
+import android.preference.ListPreference;
+import android.test.AndroidTestCase;
+
+public class ListPreferenceTest extends AndroidTestCase {
+    public void testListPreferenceSummaryFromEntries() {
+        String[] entries = { "one", "two", "three" };
+        String[] entryValues = { "1" , "2", "3" };
+        ListPreference lp = new ListPreference(getContext());
+        lp.setEntries(entries);
+        lp.setEntryValues(entryValues);
+
+        lp.setValue(entryValues[1]);
+        assertTrue(lp.getSummary() == null);
+
+        lp.setSummary("%1$s");
+        assertEquals(entries[1], lp.getSummary());
+
+        lp.setValue(entryValues[2]);
+        assertEquals(entries[2], lp.getSummary());
+
+        lp.setSummary(null);
+        assertTrue(lp.getSummary() == null);
+
+        lp.setSummary("The color is %1$s");
+        assertEquals("The color is " + entries[2], lp.getSummary());
+    }
+}
diff --git a/core/tests/hosttests/Android.mk b/core/tests/hosttests/Android.mk
index 0001201..07d99cb 100644
--- a/core/tests/hosttests/Android.mk
+++ b/core/tests/hosttests/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_MODULE := FrameworkCoreHostTests
 
-LOCAL_JAVA_LIBRARIES := hosttestlib ddmlib junit
+LOCAL_JAVA_LIBRARIES := hosttestlib ddmlib-prebuilt junit
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
index fed39c9..ebe13e1 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
@@ -16,24 +16,24 @@
 
 package android.content.pm;
 
+import com.android.ddmlib.AdbCommandRejectedException;
 import com.android.ddmlib.AndroidDebugBridge;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.InstallException;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.MultiLineReceiver;
-import com.android.ddmlib.SyncService;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.SyncException;
+import com.android.ddmlib.TimeoutException;
 import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-import com.android.ddmlib.SyncService.SyncResult;
 import com.android.ddmlib.testrunner.ITestRunListener;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.hosttest.DeviceTestCase;
-import com.android.hosttest.DeviceTestSuite;
 
 import java.io.BufferedReader;
-import java.io.File;
-import java.io.InputStreamReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.StringReader;
 import java.lang.Runtime;
 import java.lang.Process;
@@ -44,7 +44,6 @@
 import java.util.regex.Pattern;
 
 import junit.framework.Assert;
-import com.android.hosttest.DeviceTestCase;
 
 /**
  * Set of tests that verify host side install cases
@@ -128,11 +127,16 @@
      * @param methodName (optional) The method in the class of which to test
      * @param runnerName (optional) The name of the TestRunner of the test on the device to be run
      * @param params (optional) Any additional parameters to pass into the Test Runner
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      * @return the {@link CollectingTestRunListener}
      */
-    private CollectingTestRunListener doRunTests(String pkgName, String className, String
-            methodName, String runnerName, Map<String, String> params) throws IOException {
-
+    private CollectingTestRunListener doRunTests(String pkgName, String className,
+            String methodName, String runnerName, Map<String, String> params) throws IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName, runnerName,
                 mDevice);
 
@@ -163,7 +167,8 @@
      * @return true if test passed, false otherwise.
      */
     public boolean runDeviceTestsDidAllTestsPass(String pkgName, String className,
-            String methodName, String runnerName, Map<String, String> params) throws IOException {
+            String methodName, String runnerName, Map<String, String> params) throws IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         CollectingTestRunListener listener = doRunTests(pkgName, className, methodName,
                 runnerName, params);
         return listener.didAllTestsPass();
@@ -173,9 +178,15 @@
      * Runs the specified packages tests, and returns whether all tests passed or not.
      *
      * @param pkgName Android application package for tests
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      * @return true if every test passed, false otherwise.
      */
-    public boolean runDeviceTestsDidAllTestsPass(String pkgName) throws IOException {
+    public boolean runDeviceTestsDidAllTestsPass(String pkgName) throws IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         CollectingTestRunListener listener = doRunTests(pkgName, null, null, null, null);
         return listener.didAllTestsPass();
     }
@@ -183,22 +194,26 @@
     /**
      * Helper method to push a file to device
      * @param apkAppPrivatePath
-     * @throws IOException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
      */
     public void pushFile(final String localFilePath, final String destFilePath)
-            throws IOException {
-        SyncResult result = mDevice.getSyncService().pushFile(
-                localFilePath, destFilePath, new NullSyncProgressMonitor());
-        assertEquals(SyncService.RESULT_OK, result.getCode());
+            throws IOException, SyncException, TimeoutException, AdbCommandRejectedException {
+        mDevice.getSyncService().pushFile(localFilePath,
+                destFilePath, new NullSyncProgressMonitor());
     }
 
     /**
      * Helper method to install a file
      * @param localFilePath the absolute file system path to file on local host to install
      * @param reinstall set to <code>true</code> if re-install of app should be performed
-     * @throws IOException
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed
      */
-    public void installFile(final String localFilePath, final boolean replace) throws IOException {
+    public void installFile(final String localFilePath, final boolean replace) throws IOException,
+            InstallException {
         String result = mDevice.installPackage(localFilePath, replace);
         assertEquals(null, result);
     }
@@ -208,10 +223,11 @@
      * @param localFilePath the absolute file system path to file on local host to install
      * @param reinstall set to <code>true</code> if re-install of app should be performed
      * @return the string output of the failed install attempt
-     * @throws IOException
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed
      */
     public String installFileFail(final String localFilePath, final boolean replace)
-            throws IOException {
+            throws IOException, InstallException {
         String result = mDevice.installPackage(localFilePath, replace);
         assertNotNull(result);
         return result;
@@ -221,10 +237,17 @@
      * Helper method to install a file to device as forward locked
      * @param localFilePath the absolute file system path to file on local host to install
      * @param reinstall set to <code>true</code> if re-install of app should be performed
-     * @throws IOException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
     public String installFileForwardLocked(final String localFilePath, final boolean replace)
-            throws IOException {
+            throws IOException, SyncException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException, InstallException {
         String remoteFilePath = mDevice.syncPackageToDevice(localFilePath);
         InstallReceiver receiver = new InstallReceiver();
         String cmd = String.format(replace ? "pm install -r -l \"%1$s\"" :
@@ -239,9 +262,14 @@
      *
      * @param destPath the absolute path of file on device to check
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
-     * @throws IOException if adb shell command failed
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public boolean doesRemoteFileExist(String destPath) throws IOException {
+    public boolean doesRemoteFileExist(String destPath) throws IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         String lsGrep = executeShellCommand(String.format("ls %s", destPath));
         return !lsGrep.contains("No such file or directory");
     }
@@ -252,10 +280,15 @@
      * @param destPath the absolute path of the file
      * @return <code>true</code> if file exists containing given string,
      *         <code>false</code> otherwise.
-     * @throws IOException if adb shell command failed
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
     public boolean doesRemoteFileExistContainingString(String destPath, String searchString)
-            throws IOException {
+            throws IOException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         String lsResult = executeShellCommand(String.format("ls %s", destPath));
         return lsResult.contains(searchString);
     }
@@ -265,9 +298,14 @@
      *
      * @param packageName the Android manifest package to check.
      * @return <code>true</code> if package exists, <code>false</code> otherwise
-     * @throws IOException if adb shell command failed
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public boolean doesPackageExist(String packageName) throws IOException {
+    public boolean doesPackageExist(String packageName) throws IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         String pkgGrep = executeShellCommand(String.format("pm path %s", packageName));
         return pkgGrep.contains("package:");
     }
@@ -277,9 +315,14 @@
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
-     * @throws IOException if adb shell command failed
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public boolean doesAppExistOnDevice(String packageName) throws IOException {
+    public boolean doesAppExistOnDevice(String packageName) throws IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         return doesRemoteFileExistContainingString(DEVICE_APP_PATH, packageName);
     }
 
@@ -288,9 +331,14 @@
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
-     * @throws IOException if adb shell command failed
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public boolean doesAppExistOnSDCard(String packageName) throws IOException {
+    public boolean doesAppExistOnSDCard(String packageName) throws IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         return doesRemoteFileExistContainingString(SDCARD_APP_PATH, packageName);
     }
 
@@ -299,9 +347,14 @@
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
-     * @throws IOException if adb shell command failed
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public boolean doesAppExistAsForwardLocked(String packageName) throws IOException {
+    public boolean doesAppExistAsForwardLocked(String packageName) throws IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         return doesRemoteFileExistContainingString(APP_PRIVATE_PATH, packageName);
     }
 
@@ -309,9 +362,14 @@
      * Waits for device's package manager to respond.
      *
      * @throws InterruptedException
-     * @throws IOException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public void waitForPackageManager() throws InterruptedException, IOException {
+    public void waitForPackageManager() throws InterruptedException, IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "waiting for device");
         int currentWaitTime = 0;
         // poll the package manager until it returns something for android
@@ -377,9 +435,14 @@
      *
      * @param packageName The name of the package to wait to load
      * @throws InterruptedException
-     * @throws IOException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public void waitForApp(String packageName) throws InterruptedException, IOException {
+    public void waitForApp(String packageName) throws InterruptedException, IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "waiting for app to launch");
         int currentWaitTime = 0;
         // poll the package manager until it returns something for the package we're looking for
@@ -396,9 +459,14 @@
     /**
      * Helper method which executes a adb shell command and returns output as a {@link String}
      * @return the output of the command
-     * @throws IOException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public String executeShellCommand(String command) throws IOException {
+    public String executeShellCommand(String command) throws IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, String.format("adb shell %s", command));
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(command, receiver);
@@ -410,9 +478,14 @@
     /**
      * Helper method ensures we are in root mode on the host side. It returns only after
      * PackageManager is actually up and running.
-     * @throws IOException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public void runAdbRoot() throws IOException, InterruptedException {
+    public void runAdbRoot() throws IOException, InterruptedException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "adb root");
         Runtime runtime = Runtime.getRuntime();
         Process process = runtime.exec("adb root"); // adb should be in the path
@@ -430,10 +503,15 @@
     /**
      * Helper method which reboots the device and returns once the device is online again
      * and package manager is up and running (note this function is synchronous to callers).
-     * @throws IOException
      * @throws InterruptedException
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public void rebootDevice() throws IOException, InterruptedException {
+    public void rebootDevice() throws IOException, InterruptedException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         String command = "reboot"; // no need for -s since mDevice is already tied to a device
         Log.i(LOG_TAG, command);
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
@@ -498,7 +576,7 @@
         private boolean mAllTestsPassed = true;
         private String mTestRunErrorMessage = null;
 
-        public void testEnded(TestIdentifier test) {
+        public void testEnded(TestIdentifier test, Map<String, String> metrics) {
             // ignore
         }
 
@@ -509,7 +587,7 @@
             mAllTestsPassed = false;
         }
 
-        public void testRunEnded(long elapsedTime) {
+        public void testRunEnded(long elapsedTime, Map<String, String> resultBundle) {
             // ignore
         }
 
@@ -519,7 +597,7 @@
             mTestRunErrorMessage = errorMessage;
         }
 
-        public void testRunStarted(int testCount) {
+        public void testRunStarted(String runName, int testCount) {
             // ignore
         }
 
@@ -586,17 +664,23 @@
     /**
      * Helper method for installing an app to wherever is specified in its manifest, and
      * then verifying the app was installed onto SD Card.
+     * <p/>
+     * Assumes adb is running as root in device under test.
      *
      * @param the path of the apk to install
      * @param the name of the package
      * @param <code>true</code> if the app should be overwritten, <code>false</code> otherwise
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
-     * <p/>
-     * Assumes adb is running as root in device under test.
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void installAppAndVerifyExistsOnSDCard(String apkPath, String pkgName, boolean overwrite)
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         // Start with a clean slate if we're not overwriting
         if (!overwrite) {
             // cleanup test app just in case it already exists
@@ -617,17 +701,23 @@
     /**
      * Helper method for installing an app to wherever is specified in its manifest, and
      * then verifying the app was installed onto device.
+     * <p/>
+     * Assumes adb is running as root in device under test.
      *
      * @param the path of the apk to install
      * @param the name of the package
      * @param <code>true</code> if the app should be overwritten, <code>false</code> otherwise
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
-     * <p/>
-     * Assumes adb is running as root in device under test.
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void installAppAndVerifyExistsOnDevice(String apkPath, String pkgName, boolean overwrite)
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         // Start with a clean slate if we're not overwriting
         if (!overwrite) {
             // cleanup test app just in case it already exists
@@ -648,17 +738,24 @@
     /**
      * Helper method for installing an app as forward-locked, and
      * then verifying the app was installed in the proper forward-locked location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
      *
      * @param the path of the apk to install
      * @param the name of the package
      * @param <code>true</code> if the app should be overwritten, <code>false</code> otherwise
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
-     * <p/>
-     * Assumes adb is running as root in device under test.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
      */
     public void installFwdLockedAppAndVerifyExists(String apkPath,
-            String pkgName, boolean overwrite) throws IOException, InterruptedException {
+            String pkgName, boolean overwrite) throws IOException, InterruptedException,
+            InstallException, SyncException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         // Start with a clean slate if we're not overwriting
         if (!overwrite) {
             // cleanup test app just in case it already exists
@@ -679,14 +776,21 @@
 
     /**
      * Helper method for uninstalling an app.
-     *
-     * @param pkgName package name to uninstall
-     * @throws IOException if adb shell command failed
-     * @throws InterruptedException if the thread was interrupted
      * <p/>
      * Assumes adb is running as root in device under test.
+     *
+     * @param pkgName package name to uninstall
+     * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the uninstall failed.
      */
-    public void uninstallApp(String pkgName) throws IOException, InterruptedException {
+    public void uninstallApp(String pkgName) throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         mDevice.uninstallPackage(pkgName);
         // make sure its not installed anymore
         assertFalse(doesPackageExist(pkgName));
@@ -696,12 +800,18 @@
      * Helper method for clearing any installed non-system apps.
      * Useful ensuring no non-system apps are installed, and for cleaning up stale files that
      * may be lingering on the system for whatever reason.
-     *
-     * @throws IOException if adb shell command failed
      * <p/>
      * Assumes adb is running as root in device under test.
+     *
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the uninstall failed.
      */
-    public void wipeNonSystemApps() throws IOException {
+    public void wipeNonSystemApps() throws IOException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException, InstallException {
       String allInstalledPackages = executeShellCommand("pm list packages -f");
       BufferedReader outputReader = new BufferedReader(new StringReader(allInstalledPackages));
 
@@ -726,8 +836,14 @@
      *
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public void setDevicePreferredInstallLocation(InstallLocPreference pref) throws IOException {
+    public void setDevicePreferredInstallLocation(InstallLocPreference pref) throws IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         String command = "pm setInstallLocation %d";
         int locValue = 0;
         switch (pref) {
@@ -749,8 +865,14 @@
      *
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
      */
-    public InstallLocPreference getDevicePreferredInstallLocation() throws IOException {
+    public InstallLocPreference getDevicePreferredInstallLocation() throws IOException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         String result = executeShellCommand("pm getInstallLocation");
         if (result.indexOf('0') != -1) {
             return InstallLocPreference.AUTO;
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
index 1b797d5..22a2be6 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
@@ -16,13 +16,12 @@
 
 package android.content.pm;
 
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.InstallException;
 import com.android.ddmlib.Log;
-import com.android.ddmlib.MultiLineReceiver;
-import com.android.ddmlib.SyncService;
-import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-import com.android.ddmlib.SyncService.SyncResult;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.SyncException;
+import com.android.ddmlib.TimeoutException;
 import com.android.hosttest.DeviceTestCase;
 import com.android.hosttest.DeviceTestSuite;
 
@@ -156,10 +155,18 @@
      * the app, and otherwise cause the system to blow up.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
-    public void testPushAppPrivate() throws IOException, InterruptedException {
+    public void testPushAppPrivate() throws IOException, InterruptedException, InstallException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
+            SyncException {
         Log.i(LOG_TAG, "testing pushing an apk to /data/app-private");
         final String apkAppPrivatePath =  appPrivatePath + SIMPLE_APK;
 
@@ -187,12 +194,18 @@
      * @param apkName the file name of the test app apk
      * @param pkgName the package name of the test app apk
      * @param expectedLocation the file name of the test app apk
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     private void doStandardInstall(String apkName, String pkgName,
             PackageManagerHostTestUtils.InstallLocation expectedLocation)
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
 
         if (expectedLocation == PackageManagerHostTestUtils.InstallLocation.DEVICE) {
             mPMHostUtils.installAppAndVerifyExistsOnDevice(
@@ -211,12 +224,18 @@
      * Assumes adb is running as root in device under test.
      * @param preference the device's preferred location of where to install apps
      * @param expectedLocation the expected location of where the apk was installed
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
             PackageManagerHostTestUtils.InstallLocation expectedLocation)
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException, InstallException {
 
         PackageManagerHostTestUtils.InstallLocPreference savedPref =
                 PackageManagerHostTestUtils.InstallLocPreference.AUTO;
@@ -239,10 +258,16 @@
      * will install the app to the device when device's preference is auto.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppAutoLocPrefIsAuto() throws IOException, InterruptedException {
+    public void testInstallAppAutoLocPrefIsAuto() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=auto, prefer=auto gets installed on device");
         installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
                 PackageManagerHostTestUtils.InstallLocation.DEVICE);
@@ -253,10 +278,17 @@
      * will install the app to the device when device's preference is internal.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppAutoLocPrefIsInternal() throws IOException, InterruptedException {
+    public void testInstallAppAutoLocPrefIsInternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=auto, prefer=internal gets installed on device");
         installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
                 PackageManagerHostTestUtils.InstallLocation.DEVICE);
@@ -267,10 +299,17 @@
      * will install the app to the SD card when device's preference is external.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppAutoLocPrefIsExternal() throws IOException, InterruptedException {
+    public void testInstallAppAutoLocPrefIsExternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=auto, prefer=external gets installed on device");
         installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
                 PackageManagerHostTestUtils.InstallLocation.DEVICE);
@@ -283,12 +322,18 @@
      * Assumes adb is running as root in device under test.
      * @param preference the device's preferred location of where to install apps
      * @param expectedLocation the expected location of where the apk was installed
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the (un)install failed.
      */
     public void installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
             PackageManagerHostTestUtils.InstallLocation expectedLocation)
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException, InstallException {
 
         PackageManagerHostTestUtils.InstallLocPreference savedPref =
             PackageManagerHostTestUtils.InstallLocPreference.AUTO;
@@ -311,10 +356,17 @@
      * will install the app to the device when device's preference is auto.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppInternalLocPrefIsAuto() throws IOException, InterruptedException {
+    public void testInstallAppInternalLocPrefIsAuto() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=internal, prefer=auto gets installed on device");
         installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
                 PackageManagerHostTestUtils.InstallLocation.DEVICE);
@@ -325,10 +377,17 @@
      * will install the app to the device when device's preference is internal.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppInternalLocPrefIsInternal() throws IOException, InterruptedException {
+    public void testInstallAppInternalLocPrefIsInternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=internal, prefer=internal is installed on device");
         installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
                 PackageManagerHostTestUtils.InstallLocation.DEVICE);
@@ -339,10 +398,17 @@
      * will install the app to the device when device's preference is external.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppInternalLocPrefIsExternal() throws IOException, InterruptedException {
+    public void testInstallAppInternalLocPrefIsExternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=internal, prefer=external is installed on device");
         installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
                 PackageManagerHostTestUtils.InstallLocation.DEVICE);
@@ -355,12 +421,18 @@
      * Assumes adb is running as root in device under test.
      * @param preference the device's preferred location of where to install apps
      * @param expectedLocation the expected location of where the apk was installed
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
             PackageManagerHostTestUtils.InstallLocation expectedLocation)
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException, InstallException {
 
         PackageManagerHostTestUtils.InstallLocPreference savedPref =
             PackageManagerHostTestUtils.InstallLocPreference.AUTO;
@@ -384,10 +456,17 @@
      * will install the app to the device when device's preference is auto.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppExternalLocPrefIsAuto() throws IOException, InterruptedException {
+    public void testInstallAppExternalLocPrefIsAuto() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=external, pref=auto gets installed on SD Card");
         installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
                 PackageManagerHostTestUtils.InstallLocation.SDCARD);
@@ -398,10 +477,17 @@
      * will install the app to the device when device's preference is internal.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppExternalLocPrefIsInternal() throws IOException, InterruptedException {
+    public void testInstallAppExternalLocPrefIsInternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=external, pref=internal gets installed on SD Card");
         installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
                 PackageManagerHostTestUtils.InstallLocation.SDCARD);
@@ -412,10 +498,17 @@
      * will install the app to the device when device's preference is external.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppExternalLocPrefIsExternal() throws IOException, InterruptedException {
+    public void testInstallAppExternalLocPrefIsExternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installLocation=external, pref=external gets installed on SD Card");
         installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
                 PackageManagerHostTestUtils.InstallLocation.SDCARD);
@@ -427,10 +520,17 @@
      * system decide.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppNoLocPrefIsAuto() throws IOException, InterruptedException {
+    public void testInstallAppNoLocPrefIsAuto() throws IOException, InterruptedException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
+            InstallException {
         Log.i(LOG_TAG, "Test an app with no installLocation gets installed on device");
 
         PackageManagerHostTestUtils.InstallLocPreference savedPref =
@@ -456,10 +556,17 @@
      * external.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppNoLocPrefIsExternal() throws IOException, InterruptedException {
+    public void testInstallAppNoLocPrefIsExternal() throws IOException, InterruptedException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
+            InstallException {
         Log.i(LOG_TAG, "Test an app with no installLocation gets installed on SD card");
 
         PackageManagerHostTestUtils.InstallLocPreference savedPref =
@@ -485,10 +592,17 @@
      * internal.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallAppNoLocPrefIsInternal() throws IOException, InterruptedException {
+    public void testInstallAppNoLocPrefIsInternal() throws IOException, InterruptedException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
+            InstallException {
         Log.i(LOG_TAG, "Test an app with no installLocation gets installed on device");
 
         PackageManagerHostTestUtils.InstallLocPreference savedPref =
@@ -513,10 +627,18 @@
      * forward-locked will get installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallFwdLockedAppInternal() throws IOException, InterruptedException {
+    public void testInstallFwdLockedAppInternal() throws IOException, InterruptedException,
+            InstallException, SyncException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");
 
         try {
@@ -534,10 +656,18 @@
      * forward-locked will get installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallFwdLockedAppExternal() throws IOException, InterruptedException {
+    public void testInstallFwdLockedAppExternal() throws IOException, InterruptedException,
+            InstallException, SyncException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");
 
         try {
@@ -555,10 +685,18 @@
      * forward-locked will get installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallFwdLockedAppAuto() throws IOException, InterruptedException {
+    public void testInstallFwdLockedAppAuto() throws IOException, InterruptedException,
+            InstallException, SyncException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test an app with installLoc set to Auto gets installed to app-private");
 
         try {
@@ -576,10 +714,18 @@
      * forward-locked installed will get installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
-    public void testInstallFwdLockedAppNone() throws IOException, InterruptedException {
+    public void testInstallFwdLockedAppNone() throws IOException, InterruptedException,
+            InstallException, SyncException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test an app with no installLoc set gets installed to app-private");
 
         try {
@@ -597,14 +743,21 @@
      * uninstall it, and reinstall it onto the SD card.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     // TODO: This currently relies on the app's manifest to switch from device to
     // SD card install locations. We might want to make Device's installPackage()
     // accept a installLocation flag so we can install a package to the
     // destination of our choosing.
-    public void testReinstallInternalToExternal() throws IOException, InterruptedException {
+    public void testReinstallInternalToExternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installing an app first to the device, then to the SD Card");
 
         try {
@@ -625,14 +778,21 @@
      * uninstall it, and reinstall it onto the device.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     // TODO: This currently relies on the app's manifest to switch from device to
     // SD card install locations. We might want to make Device's installPackage()
     // accept a installLocation flag so we can install a package to the
     // destination of our choosing.
-    public void testReinstallExternalToInternal() throws IOException, InterruptedException {
+    public void testReinstallExternalToInternal() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installing an app first to the SD Care, then to the device");
 
         try {
@@ -655,10 +815,16 @@
      * the update onto the SD card as well when location is set to external for both versions
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testUpdateBothExternal() throws IOException, InterruptedException {
+    public void testUpdateBothExternal() throws IOException, InterruptedException, InstallException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
 
         try {
@@ -681,10 +847,16 @@
      * updated apps' manifest file.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testUpdateToSDCard() throws IOException, InterruptedException {
+    public void testUpdateToSDCard() throws IOException, InterruptedException, InstallException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
 
         try {
@@ -706,10 +878,17 @@
      * the update onto the device if the manifest has changed to installLocation=internalOnly
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
-    public void testUpdateSDCardToDevice() throws IOException, InterruptedException {
+    public void testUpdateSDCardToDevice() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating an app on the SD card to the Device through manifest change");
 
         try {
@@ -731,11 +910,18 @@
      * the update onto the device's forward-locked location
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndUpdateExternalLocForwardLockedApp()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, SyncException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating a forward-locked app marked preferExternal");
 
         try {
@@ -757,11 +943,18 @@
      * the update onto the device's forward-locked location
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndUpdateNoLocForwardLockedApp()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, SyncException,
+            TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating a forward-locked app with no installLocation pref set");
 
         try {
@@ -783,11 +976,18 @@
      * and then launched without crashing.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws SyncException if the sync failed for another reason.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchAllPermsAppOnSD()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app with all perms set, installed on SD card");
 
         try {
@@ -808,11 +1008,17 @@
      * run without permissions errors.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchFLPermsAppOnSD()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app with location perms set, installed on SD card");
 
         try {
@@ -833,11 +1039,17 @@
      * run without permissions errors.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchBTPermsAppOnSD()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app with bluetooth perms set, installed on SD card");
 
         try {
@@ -858,11 +1070,17 @@
      * SecurityException when launched if its other shared apps are not installed.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchSharedPermsAppOnSD_NoPerms()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app with no explicit perms set, installed on SD card");
 
         try {
@@ -888,11 +1106,17 @@
      * shared apps are installed.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchSharedPermsAppOnSD_GrantedPerms()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app with no explicit perms set, installed on SD card");
 
         try {
@@ -921,11 +1145,17 @@
      * run without permissions errors even after a reboot
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchFLPermsAppOnSD_Reboot()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app with location perms set, installed on SD card");
 
         try {
@@ -951,11 +1181,17 @@
      * shared apps are installed, even after a reboot.
      * <p/>
      * Assumes adb is running as root in device under test.
-     * @throws IOException if adb shell command failed
      * @throws InterruptedException if the thread was interrupted
+     * @throws TimeoutException in case of a timeout on the connection.
+     * @throws AdbCommandRejectedException if adb rejects the command
+     * @throws ShellCommandUnresponsiveException if the device did not output anything for
+     * a period longer than the max time to output.
+     * @throws IOException if connection to device was lost.
+     * @throws InstallException if the install failed.
      */
     public void testInstallAndLaunchSharedPermsAppOnSD_Reboot()
-            throws IOException, InterruptedException {
+            throws IOException, InterruptedException, InstallException, TimeoutException,
+            AdbCommandRejectedException, ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test launching an app on SD, with no explicit perms set after reboot");
 
         try {
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
index 715c55b..a2a5dd3 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
@@ -16,8 +16,11 @@
 
 package android.content.pm;
 
-import com.android.ddmlib.IDevice;
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.InstallException;
 import com.android.ddmlib.Log;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
 import com.android.hosttest.DeviceTestCase;
 import com.android.hosttest.DeviceTestSuite;
 
@@ -138,7 +141,9 @@
      * <p/>
      * Assumes adb is running as root in device under test.
      */
-    public void testUpdateAppManyTimesOnSD() throws IOException, InterruptedException {
+    public void testUpdateAppManyTimesOnSD() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating an app on SD numerous times");
 
         // cleanup test app just in case it already exists
@@ -173,7 +178,9 @@
      * <p/>
      * Assumes adb is running as root in device under test.
      */
-    public void testUninstallReinstallAppOnSDManyTimes() throws IOException, InterruptedException {
+    public void testUninstallReinstallAppOnSDManyTimes() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
 
         // cleanup test app just in case it was already exists
@@ -207,7 +214,9 @@
      * <p/>
      * Assumes adb is running as root in device under test.
      */
-    public void testInstallManyLargeAppsOnSD() throws IOException, InterruptedException {
+    public void testInstallManyLargeAppsOnSD() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installing 20 large apps onto the sd card");
 
         try {
@@ -251,7 +260,9 @@
      * <p/>
      * Assumes adb is running as root in device under test.
      */
-    public void testInstallManyAppsOnSD() throws IOException, InterruptedException {
+    public void testInstallManyAppsOnSD() throws IOException, InterruptedException,
+            InstallException, TimeoutException, AdbCommandRejectedException,
+            ShellCommandUnresponsiveException {
         Log.i(LOG_TAG, "Test installing 500 small apps onto SD");
 
         try {
diff --git a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
index df781bf..a94555c 100644
--- a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
+++ b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
@@ -17,20 +17,12 @@
 package android.net;
 
 import android.content.pm.PackageManagerHostTestUtils;
-import android.content.pm.PackageManagerHostTestUtils.CollectingTestRunListener;
 
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.Log;
-import com.android.ddmlib.MultiLineReceiver;
-import com.android.ddmlib.SyncService;
-import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-import com.android.ddmlib.SyncService.SyncResult;
 import com.android.hosttest.DeviceTestCase;
 import com.android.hosttest.DeviceTestSuite;
 
 import java.io.File;
-import java.io.IOException;
 import java.util.Hashtable;
 
 import junit.framework.Test;
diff --git a/docs/html/community/index.jd b/docs/html/community/index.jd
index 3e69de4..23203c1 100644
--- a/docs/html/community/index.jd
+++ b/docs/html/community/index.jd
@@ -4,10 +4,10 @@
 
 	<div id="mainBodyFluid">
 <h1>Community</h1>
-<p>Welcome to the Android developers community! We're glad you're here and invite you to participate in these discussions. Before posting, please read the <a href="http://source.android.com/discuss/android-discussion-groups-charter">Groups Charter</a> that covers the community guidelines.</p>
+<p>Welcome to the Android developers community! We're glad you're here and invite you to participate in these discussions. Before posting, please read the <a href="http://source.android.com/community/groups-charter.html">Groups Charter</a> that covers the community guidelines.</p>
 
 <p class="note"><strong>Note:</strong> If you are seeking discussion about Android source code (not application development),
-then please refer to the <a href="http://source.android.com/discuss">Open Source Project Mailing lists</a>.</p>
+then please refer to the <a href="http://source.android.com/community">Open Source Project Mailing lists</a>.</p>
 
 <p style="margin-bottom:.5em"><strong>Contents</strong></p>
 <ol class="toc">
@@ -31,7 +31,7 @@
 As you write your post, please do the following:
 <ol>
 <li><b>Read
-the <a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">mailing list charter</a></b> that covers the community guidelines. 
+the <a href="http://source.android.com/community/groups-charter.html">mailing list charter</a></b> that covers the community guidelines. 
 </li>
 <li><b>Select the most appropriate mailing list for your question</b>. There are several different lists for 
 developers, described below.</li>
diff --git a/docs/html/guide/topics/resources/animation-resource.jd b/docs/html/guide/topics/resources/animation-resource.jd
index e0ce051..972dd72 100644
--- a/docs/html/guide/topics/resources/animation-resource.jd
+++ b/docs/html/guide/topics/resources/animation-resource.jd
@@ -65,10 +65,10 @@
         android:pivotX="<em>float</em>"
         android:pivotY="<em>float</em>" /&gt;
     &lt;<a href="#translate-element">translate</a>
-        android:fromX="<em>float</em>"
-        android:toX="<em>float</em>"
-        android:fromY="<em>float</em>"
-        android:toY="<em>float</em>" /&gt;
+        android:fromXDelta="<em>float</em>"
+        android:toXDelta="<em>float</em>"
+        android:fromYDelta="<em>float</em>"
+        android:toYDelta="<em>float</em>" /&gt;
     &lt;<a href="#rotate-element">rotate</a>
         android:fromDegrees="<em>float</em>"
         android:toDegrees="<em>float</em>"
@@ -212,10 +212,10 @@
     android:shareInterpolator="false">
     &lt;scale
         android:interpolator="@android:anim/accelerate_decelerate_interpolator"
-        android:fromXScale="1.0" 
-        android:toXScale="1.4" 
-        android:fromYScale="1.0" 
-        android:toYScale="0.6" 
+        android:fromXScale="1.0"
+        android:toXScale="1.4"
+        android:fromYScale="1.0"
+        android:toYScale="0.6"
         android:pivotX="50%"
         android:pivotY="50%"
         android:fillAfter="false"
@@ -224,18 +224,18 @@
         android:interpolator="@android:anim/accelerate_interpolator"
         android:startOffset="700">
         &lt;scale
-            android:fromXScale="1.4" 
+            android:fromXScale="1.4"
             android:toXScale="0.0"
             android:fromYScale="0.6"
-            android:toYScale="0.0" 
-            android:pivotX="50%" 
-            android:pivotY="50%" 
+            android:toYScale="0.0"
+            android:pivotX="50%"
+            android:pivotY="50%"
             android:duration="400" />
         &lt;rotate
-            android:fromDegrees="0" 
+            android:fromDegrees="0"
             android:toDegrees="-45"
-            android:toYScale="0.0" 
-            android:pivotX="50%" 
+            android:toYScale="0.0"
+            android:pivotX="50%"
             android:pivotY="50%"
             android:duration="400" />
     &lt;/set>
diff --git a/docs/html/intl/ja/community/index.jd b/docs/html/intl/ja/community/index.jd
index 659aee7..490b23f 100644
--- a/docs/html/intl/ja/community/index.jd
+++ b/docs/html/intl/ja/community/index.jd
@@ -4,9 +4,9 @@
 
 	<div id="mainBodyFluid">
 			<h1>コミュニティ</h1>
-			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/discuss/android-discussion-groups-charter">グループの趣意</a>をお読みください。</p>
+			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/community/groups-charter.html">グループの趣意</a>をお読みください。</p>
 
-<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/discuss">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
+<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/community">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
 
 <p style="margin-bottom:.5em"><strong>目次</strong></p>
 <ol class="toc">
@@ -28,7 +28,7 @@
 
 <p>質問への答えが見つからない場合、コミュニティで質問することをおすすめします。投稿する際は、次の手順に従ってください。
 <ol>
-<li>コミュニティ ガイドラインが記載されている<b><a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">Android メーリングリストの趣意</a></b>をお読みください。 
+<li>コミュニティ ガイドラインが記載されている<b><a href="http://source.android.com/community/groups-charter.html">Android メーリングリストの趣意</a></b>をお読みください。 
 </li>
 <li><b>質問に最適なメーリング リストを選択してください</b>。後述するように、デベロッパー向けのメーリング リストは何種類かに分かれています。</li>
 <li>
diff --git a/docs/html/intl/ja/resources/community-groups.jd b/docs/html/intl/ja/resources/community-groups.jd
index c99b1f8..ecedde1 100644
--- a/docs/html/intl/ja/resources/community-groups.jd
+++ b/docs/html/intl/ja/resources/community-groups.jd
@@ -4,9 +4,9 @@
 
 	<div id="mainBodyFluid">
 			<h1>コミュニティ</h1>
-			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/discuss/android-discussion-groups-charter">グループの趣意</a>をお読みください。</p>
+			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/community/groups-charter.html">グループの趣意</a>をお読みください。</p>
 
-<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/discuss">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
+<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/community">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
 
 <p style="margin-bottom:.5em"><strong>目次</strong></p>
 <ol class="toc">
@@ -28,7 +28,7 @@
 
 <p>質問への答えが見つからない場合、コミュニティで質問することをおすすめします。投稿する際は、次の手順に従ってください。
 <ol>
-<li>コミュニティ ガイドラインが記載されている<b><a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">Android メーリングリストの趣意</a></b>をお読みください。 
+<li>コミュニティ ガイドラインが記載されている<b><a href="http://source.android.com/community/groups-charter.html">Android メーリングリストの趣意</a></b>をお読みください。 
 </li>
 <li><b>質問に最適なメーリング リストを選択してください</b>。後述するように、デベロッパー向けのメーリング リストは何種類かに分かれています。</li>
 <li>
diff --git a/docs/html/resources/articles/painless-threading.jd b/docs/html/resources/articles/painless-threading.jd
index 921f4df..17cec35 100644
--- a/docs/html/resources/articles/painless-threading.jd
+++ b/docs/html/resources/articles/painless-threading.jd
@@ -108,7 +108,7 @@
   new DownloadImageTask().execute("http://example.com/image.png");
 }
 
-private class DownloadImageTask extends AsyncTask&lt;string, void,="" bitmap=""&gt; {
+private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
      protected Bitmap doInBackground(String... urls) {
          return loadImageFromNetwork(urls[0]);
      }
diff --git a/docs/html/resources/community-groups.jd b/docs/html/resources/community-groups.jd
index ef1960b..599c4ae 100644
--- a/docs/html/resources/community-groups.jd
+++ b/docs/html/resources/community-groups.jd
@@ -22,7 +22,7 @@
 
 <p>Welcome to the Android developers community! We're glad you're here and invite you to participate in discussions with other Android application developers on topics that interest you.</p>
 
-<p>The lists on this page are primarily for discussion about Android application development. If you are seeking discussion about Android source code (not application development), then please refer to the <a href="http://source.android.com/discuss">Open Source Project Mailing lists</a>.</p>
+<p>The lists on this page are primarily for discussion about Android application development. If you are seeking discussion about Android source code (not application development), then please refer to the <a href="http://source.android.com/community">Open Source Project Mailing lists</a>.</p>
 
 <h2 id="StackOverflow">Stack Overflow</h2>
 
diff --git a/drm/common/Android.mk b/drm/common/Android.mk
new file mode 100644
index 0000000..808b2c2
--- /dev/null
+++ b/drm/common/Android.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    DrmConstraints.cpp \
+    DrmConvertedStatus.cpp \
+    DrmEngineBase.cpp \
+    DrmInfo.cpp \
+    DrmInfoRequest.cpp \
+    DrmInfoStatus.cpp \
+    DrmRights.cpp \
+    DrmSupportInfo.cpp \
+    IDrmIOService.cpp \
+    IDrmManagerService.cpp \
+    IDrmServiceListener.cpp \
+    DrmInfoEvent.cpp \
+    ReadWriteUtils.cpp
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/base/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/plugins/common/include
+
+LOCAL_MODULE:= libdrmframeworkcommon
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/common/DrmConstraints.cpp b/drm/common/DrmConstraints.cpp
new file mode 100644
index 0000000..4a4d798
--- /dev/null
+++ b/drm/common/DrmConstraints.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <drm/DrmConstraints.h>
+
+using namespace android;
+
+const String8 DrmConstraints::MAX_REPEAT_COUNT("max_repeat_count");
+const String8 DrmConstraints::REMAINING_REPEAT_COUNT("remaining_repeat_count");
+const String8 DrmConstraints::LICENSE_START_TIME("license_start_time");
+const String8 DrmConstraints::LICENSE_EXPIRY_TIME("license_expiry_time");
+const String8 DrmConstraints::LICENSE_AVAILABLE_TIME("license_available_time");
+const String8 DrmConstraints::EXTENDED_METADATA("extended_metadata");
+
+int DrmConstraints::getCount(void) const {
+    return mConstraintMap.size();
+}
+
+status_t DrmConstraints::put(const String8* key, const char* value) {
+    int length = strlen(value);
+    char* charValue = new char[length + 1];
+    if (NULL != charValue) {
+        strncpy(charValue, value, length);
+        charValue[length] = '\0';
+        mConstraintMap.add(*key, charValue);
+    }
+    return DRM_NO_ERROR;
+}
+
+String8 DrmConstraints::get(const String8& key) const {
+    if (NULL != getValue(&key)) {
+        return String8(getValue(&key));
+    }
+    return String8("");
+}
+
+const char* DrmConstraints::getValue(const String8* key) const {
+    if (NAME_NOT_FOUND != mConstraintMap.indexOfKey(*key)) {
+        return mConstraintMap.valueFor(*key);
+    }
+    return NULL;
+}
+
+const char* DrmConstraints::getAsByteArray(const String8* key) const {
+    return getValue(key);
+}
+
+bool DrmConstraints::KeyIterator::hasNext() {
+    return mIndex < mDrmConstraints->mConstraintMap.size();
+}
+
+const String8& DrmConstraints::KeyIterator::next() {
+    const String8& key = mDrmConstraints->mConstraintMap.keyAt(mIndex);
+    mIndex++;
+    return key;
+}
+
+DrmConstraints::KeyIterator DrmConstraints::keyIterator() {
+    return KeyIterator(this);
+}
+
+DrmConstraints::KeyIterator::KeyIterator(const DrmConstraints::KeyIterator& keyIterator)
+    : mDrmConstraints(keyIterator.mDrmConstraints),
+      mIndex(keyIterator.mIndex) {
+}
+
+DrmConstraints::KeyIterator& DrmConstraints::KeyIterator::operator=(
+    const DrmConstraints::KeyIterator& keyIterator) {
+    mDrmConstraints = keyIterator.mDrmConstraints;
+    mIndex = keyIterator.mIndex;
+    return *this;
+}
+
+
+DrmConstraints::Iterator DrmConstraints::iterator() {
+    return Iterator(this);
+}
+
+DrmConstraints::Iterator::Iterator(const DrmConstraints::Iterator& iterator) :
+    mDrmConstraints(iterator.mDrmConstraints),
+    mIndex(iterator.mIndex) {
+}
+
+DrmConstraints::Iterator& DrmConstraints::Iterator::operator=(
+    const DrmConstraints::Iterator& iterator) {
+    mDrmConstraints = iterator.mDrmConstraints;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool DrmConstraints::Iterator::hasNext() {
+    return mIndex < mDrmConstraints->mConstraintMap.size();
+}
+
+String8 DrmConstraints::Iterator::next() {
+    String8 value = String8(mDrmConstraints->mConstraintMap.editValueAt(mIndex));
+    mIndex++;
+    return value;
+}
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java b/drm/common/DrmConvertedStatus.cpp
similarity index 64%
copy from telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
copy to drm/common/DrmConvertedStatus.cpp
index 86de366..5d035f5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
+++ b/drm/common/DrmConvertedStatus.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+#include <drm/DrmConvertedStatus.h>
 
-import android.util.AndroidException;
+using namespace android;
 
+DrmConvertedStatus::DrmConvertedStatus(
+    int _statusCode, const DrmBuffer* _convertedData, int _offset) :
+    statusCode(_statusCode),
+    convertedData(_convertedData),
+    offset(_offset) {
 
-/**
- * Base class for all the exceptions in STK service.
- *
- * {@hide}
- */
-class StkException extends AndroidException {
-    public StkException() {
-        super();
-    }
 }
+
diff --git a/drm/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
new file mode 100644
index 0000000..17cdf544
--- /dev/null
+++ b/drm/common/DrmEngineBase.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DrmEngineBase.h"
+
+using namespace android;
+
+DrmEngineBase::DrmEngineBase() {
+
+}
+
+DrmEngineBase::~DrmEngineBase() {
+
+}
+
+DrmConstraints* DrmEngineBase::getConstraints(
+    int uniqueId, const String8* path, int action) {
+    return onGetConstraints(uniqueId, path, action);
+}
+
+status_t DrmEngineBase::initialize(int uniqueId) {
+    return onInitialize(uniqueId);
+}
+
+status_t DrmEngineBase::setOnInfoListener(
+    int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
+    return onSetOnInfoListener(uniqueId, infoListener);
+}
+
+status_t DrmEngineBase::terminate(int uniqueId) {
+    return onTerminate(uniqueId);
+}
+
+bool DrmEngineBase::canHandle(int uniqueId, const String8& path) {
+    return onCanHandle(uniqueId, path);
+}
+
+DrmInfoStatus* DrmEngineBase::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    return onProcessDrmInfo(uniqueId, drmInfo);
+}
+
+status_t DrmEngineBase::saveRights(
+            int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    return onSaveRights(uniqueId, drmRights, rightsPath, contentPath);
+}
+
+DrmInfo* DrmEngineBase::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    return onAcquireDrmInfo(uniqueId, drmInfoRequest);
+}
+
+String8 DrmEngineBase::getOriginalMimeType(int uniqueId, const String8& path) {
+    return onGetOriginalMimeType(uniqueId, path);
+}
+
+int DrmEngineBase::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
+    return onGetDrmObjectType(uniqueId, path, mimeType);
+}
+
+int DrmEngineBase::checkRightsStatus(int uniqueId, const String8& path, int action) {
+    return onCheckRightsStatus(uniqueId, path, action);
+}
+
+status_t DrmEngineBase::consumeRights(
+    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    return onConsumeRights(uniqueId, decryptHandle, action, reserve);
+}
+
+status_t DrmEngineBase::setPlaybackStatus(
+    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    return onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+}
+
+bool DrmEngineBase::validateAction(
+    int uniqueId, const String8& path,
+    int action, const ActionDescription& description) {
+    return onValidateAction(uniqueId, path, action, description);
+}
+
+status_t DrmEngineBase::removeRights(int uniqueId, const String8& path) {
+    return onRemoveRights(uniqueId, path);
+}
+
+status_t DrmEngineBase::removeAllRights(int uniqueId) {
+    return onRemoveAllRights(uniqueId);
+}
+
+status_t DrmEngineBase::openConvertSession(int uniqueId, int convertId) {
+    return onOpenConvertSession(uniqueId, convertId);
+}
+
+DrmConvertedStatus* DrmEngineBase::convertData(
+    int uniqueId, int convertId, const DrmBuffer* inputData) {
+    return onConvertData(uniqueId, convertId, inputData);
+}
+
+DrmConvertedStatus* DrmEngineBase::closeConvertSession(int uniqueId, int convertId) {
+    return onCloseConvertSession(uniqueId, convertId);
+}
+
+DrmSupportInfo* DrmEngineBase::getSupportInfo(int uniqueId) {
+    return onGetSupportInfo(uniqueId);
+}
+
+status_t DrmEngineBase::openDecryptSession(
+    int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length) {
+    return onOpenDecryptSession(uniqueId, decryptHandle, fd, offset, length);
+}
+
+status_t DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    return onCloseDecryptSession(uniqueId, decryptHandle);
+}
+
+status_t DrmEngineBase::initializeDecryptUnit(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    return onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
+}
+
+status_t DrmEngineBase::decrypt(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+}
+
+status_t DrmEngineBase::finalizeDecryptUnit(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    return onFinalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+}
+
+ssize_t DrmEngineBase::pread(
+    int uniqueId, DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off_t offset) {
+    return onPread(uniqueId, decryptHandle, buffer, numBytes, offset);
+}
+
diff --git a/drm/common/DrmInfo.cpp b/drm/common/DrmInfo.cpp
new file mode 100644
index 0000000..ddcab33
--- /dev/null
+++ b/drm/common/DrmInfo.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <drm/DrmInfo.h>
+
+using namespace android;
+
+DrmInfo::DrmInfo(int infoType, const DrmBuffer& drmBuffer, const String8& mimeType) :
+    mInfoType(infoType),
+    mData(drmBuffer),
+    mMimeType(mimeType) {
+
+}
+
+int DrmInfo::getInfoType(void) const {
+    return mInfoType;
+}
+
+String8 DrmInfo::getMimeType(void) const {
+    return mMimeType;
+}
+
+const DrmBuffer& DrmInfo::getData(void) const {
+    return mData;
+}
+
+int DrmInfo::getCount(void) const {
+    return mAttributes.size();
+}
+
+status_t DrmInfo::put(const String8& key, const String8& value) {
+    mAttributes.add(key, value);
+    return DRM_NO_ERROR;
+}
+
+String8 DrmInfo::get(const String8& key) const {
+    if (NAME_NOT_FOUND != mAttributes.indexOfKey(key)) {
+        return mAttributes.valueFor(key);
+    }
+    return String8("");
+}
+
+int DrmInfo::indexOfKey(const String8& key) const {
+    return mAttributes.indexOfKey(key);
+}
+
+DrmInfo::KeyIterator DrmInfo::keyIterator() const {
+    return KeyIterator(this);
+}
+
+DrmInfo::Iterator DrmInfo::iterator() const {
+    return Iterator(this);
+}
+
+// KeyIterator implementation
+DrmInfo::KeyIterator::KeyIterator(const DrmInfo::KeyIterator& keyIterator) :
+    mDrmInfo(keyIterator.mDrmInfo), mIndex(keyIterator.mIndex) {
+
+}
+
+bool DrmInfo::KeyIterator::hasNext() {
+    return (mIndex < mDrmInfo->mAttributes.size());
+}
+
+const String8& DrmInfo::KeyIterator::next() {
+    const String8& key = mDrmInfo->mAttributes.keyAt(mIndex);
+    mIndex++;
+    return key;
+}
+
+DrmInfo::KeyIterator& DrmInfo::KeyIterator::operator=(const DrmInfo::KeyIterator& keyIterator) {
+    mDrmInfo = keyIterator.mDrmInfo;
+    mIndex = keyIterator.mIndex;
+    return *this;
+}
+
+// Iterator implementation
+DrmInfo::Iterator::Iterator(const DrmInfo::Iterator& iterator)
+    : mDrmInfo(iterator.mDrmInfo), mIndex(iterator.mIndex) {
+
+}
+
+DrmInfo::Iterator& DrmInfo::Iterator::operator=(const DrmInfo::Iterator& iterator) {
+    mDrmInfo = iterator.mDrmInfo;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool DrmInfo::Iterator::hasNext() {
+    return mIndex < mDrmInfo->mAttributes.size();
+}
+
+String8& DrmInfo::Iterator::next() {
+    String8& value = mDrmInfo->mAttributes.editValueAt(mIndex);
+    mIndex++;
+    return value;
+}
+
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
new file mode 100644
index 0000000..8d115a8
--- /dev/null
+++ b/drm/common/DrmInfoEvent.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+#include <drm/DrmInfoEvent.h>
+
+using namespace android;
+
+DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8& message)
+    : mUniqueId(uniqueId),
+      mInfoType(infoType),
+      mMessage(message) {
+
+}
+
+int DrmInfoEvent::getUniqueId() const {
+    return mUniqueId;
+}
+
+int DrmInfoEvent::getType() const {
+    return mInfoType;
+}
+
+const String8& DrmInfoEvent::getMessage() const {
+    return mMessage;
+}
+
diff --git a/drm/common/DrmInfoRequest.cpp b/drm/common/DrmInfoRequest.cpp
new file mode 100644
index 0000000..a646859
--- /dev/null
+++ b/drm/common/DrmInfoRequest.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <drm/DrmInfoRequest.h>
+
+using namespace android;
+
+const String8 DrmInfoRequest::ACCOUNT_ID("account_id");
+const String8 DrmInfoRequest::SUBSCRIPTION_ID("subscription_id");
+
+DrmInfoRequest::DrmInfoRequest(int infoType, const String8& mimeType) :
+    mInfoType(infoType), mMimeType(mimeType) {
+
+}
+
+String8 DrmInfoRequest::getMimeType(void) const {
+    return mMimeType;
+}
+
+int DrmInfoRequest::getInfoType(void) const {
+    return mInfoType;
+}
+
+int DrmInfoRequest::getCount(void) const {
+    return mRequestInformationMap.size();
+}
+
+status_t DrmInfoRequest::put(const String8& key, const String8& value) {
+    mRequestInformationMap.add(key, value);
+    return DRM_NO_ERROR;
+}
+
+String8 DrmInfoRequest::get(const String8& key) const {
+    if (NAME_NOT_FOUND != mRequestInformationMap.indexOfKey(key)) {
+        return mRequestInformationMap.valueFor(key);
+    }
+    return String8("");
+}
+
+DrmInfoRequest::KeyIterator DrmInfoRequest::keyIterator() const {
+    return KeyIterator(this);
+}
+
+DrmInfoRequest::Iterator DrmInfoRequest::iterator() const {
+    return Iterator(this);
+}
+
+// KeyIterator implementation
+DrmInfoRequest::KeyIterator::KeyIterator(const DrmInfoRequest::KeyIterator& keyIterator)
+    : mDrmInfoRequest(keyIterator.mDrmInfoRequest),
+      mIndex(keyIterator.mIndex) {
+
+}
+
+bool DrmInfoRequest::KeyIterator::hasNext() {
+    return (mIndex < mDrmInfoRequest->mRequestInformationMap.size());
+}
+
+const String8& DrmInfoRequest::KeyIterator::next() {
+    const String8& key = mDrmInfoRequest->mRequestInformationMap.keyAt(mIndex);
+    mIndex++;
+    return key;
+}
+
+DrmInfoRequest::KeyIterator& DrmInfoRequest::KeyIterator::operator=(
+    const DrmInfoRequest::KeyIterator& keyIterator) {
+    mDrmInfoRequest = keyIterator.mDrmInfoRequest;
+    mIndex = keyIterator.mIndex;
+    return *this;
+}
+
+// Iterator implementation
+DrmInfoRequest::Iterator::Iterator(const DrmInfoRequest::Iterator& iterator) :
+    mDrmInfoRequest(iterator.mDrmInfoRequest), mIndex(iterator.mIndex) {
+}
+
+DrmInfoRequest::Iterator& DrmInfoRequest::Iterator::operator=(
+    const DrmInfoRequest::Iterator& iterator) {
+    mDrmInfoRequest = iterator.mDrmInfoRequest;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool DrmInfoRequest::Iterator::hasNext() {
+    return mIndex < mDrmInfoRequest->mRequestInformationMap.size();
+}
+
+String8& DrmInfoRequest::Iterator::next() {
+    String8& value = mDrmInfoRequest->mRequestInformationMap.editValueAt(mIndex);
+    mIndex++;
+    return value;
+}
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java b/drm/common/DrmInfoStatus.cpp
similarity index 64%
copy from telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
copy to drm/common/DrmInfoStatus.cpp
index 86de366..f3a1516 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
+++ b/drm/common/DrmInfoStatus.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+#include <drm/DrmInfoStatus.h>
 
-import android.util.AndroidException;
+using namespace android;
 
+DrmInfoStatus::DrmInfoStatus(
+    int _statusCode, const DrmBuffer* _drmBuffer, const String8& _mimeType) :
+    statusCode(_statusCode),
+    drmBuffer(_drmBuffer),
+    mimeType(_mimeType) {
 
-/**
- * Base class for all the exceptions in STK service.
- *
- * {@hide}
- */
-class StkException extends AndroidException {
-    public StkException() {
-        super();
-    }
 }
+
diff --git a/drm/common/DrmRights.cpp b/drm/common/DrmRights.cpp
new file mode 100644
index 0000000..3aecb3d
--- /dev/null
+++ b/drm/common/DrmRights.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <drm/DrmRights.h>
+#include <ReadWriteUtils.h>
+
+using namespace android;
+
+DrmRights::DrmRights(const String8& rightsFilePath, const String8& mimeType,
+            const String8& accountId, const String8& subscriptionId) :
+    mMimeType(mimeType),
+    mAccountId(accountId),
+    mSubscriptionId(subscriptionId),
+    mRightsFromFile(NULL) {
+    int rightsLength = 0;
+    if (String8("") != rightsFilePath) {
+        rightsLength = ReadWriteUtils::readBytes(rightsFilePath, &mRightsFromFile);
+    }
+    mData = DrmBuffer(mRightsFromFile, rightsLength);
+}
+
+DrmRights::DrmRights(const DrmBuffer& rightsData, const String8& mimeType,
+            const String8& accountId, const String8& subscriptionId) :
+    mData(rightsData),
+    mMimeType(mimeType),
+    mAccountId(accountId),
+    mSubscriptionId(subscriptionId),
+    mRightsFromFile(NULL) {
+}
+
+DrmRights::~DrmRights() {
+    delete[] mRightsFromFile; mRightsFromFile = NULL;
+}
+
+const DrmBuffer& DrmRights::getData(void) const {
+    return mData;
+}
+
+String8 DrmRights::getMimeType(void) const {
+    return mMimeType;
+}
+
+String8 DrmRights::getAccountId(void) const {
+    return mAccountId;
+}
+
+String8 DrmRights::getSubscriptionId(void) const {
+    return mSubscriptionId;
+}
+
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
new file mode 100644
index 0000000..ffc8953
--- /dev/null
+++ b/drm/common/DrmSupportInfo.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <drm/DrmSupportInfo.h>
+
+using namespace android;
+
+DrmSupportInfo::DrmSupportInfo() {
+
+}
+
+DrmSupportInfo::DrmSupportInfo(const DrmSupportInfo& drmSupportInfo):
+    mMimeTypeVector(drmSupportInfo.mMimeTypeVector),
+    mFileSuffixVector(drmSupportInfo.mFileSuffixVector),
+    mDescription(drmSupportInfo.mDescription) {
+
+}
+
+bool DrmSupportInfo::operator<(const DrmSupportInfo& drmSupportInfo) const {
+    // Do we need to check mMimeTypeVector & mFileSuffixVector ?
+    // Note Vector doesn't overrides "<" operator
+    return mDescription < drmSupportInfo.mDescription;
+}
+
+bool DrmSupportInfo::operator==(const DrmSupportInfo& drmSupportInfo) const {
+    // Do we need to check mMimeTypeVector & mFileSuffixVector ?
+    // Note Vector doesn't overrides "==" operator
+    return (mDescription == drmSupportInfo.mDescription);
+}
+
+bool DrmSupportInfo::isSupportedMimeType(const String8& mimeType) const {
+    for (unsigned int i = 0; i < mMimeTypeVector.size(); i++) {
+        const String8 item = mMimeTypeVector.itemAt(i);
+
+        if (String8("") != mimeType && item.find(mimeType) != -1) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DrmSupportInfo::isSupportedFileSuffix(const String8& fileType) const {
+    for (unsigned int i = 0; i < mFileSuffixVector.size(); i++) {
+        const String8 item = mFileSuffixVector.itemAt(i);
+
+        if (String8("") != fileType && item.find(fileType) != -1) {
+            return true;
+        }
+    }
+    return false;
+}
+
+DrmSupportInfo& DrmSupportInfo::operator=(const DrmSupportInfo& drmSupportInfo) {
+    mMimeTypeVector = drmSupportInfo.mMimeTypeVector;
+    mFileSuffixVector = drmSupportInfo.mFileSuffixVector;
+    mDescription = drmSupportInfo.mDescription;
+    return *this;
+}
+
+int DrmSupportInfo::getMimeTypeCount(void) const {
+    return mMimeTypeVector.size();
+}
+
+int DrmSupportInfo::getFileSuffixCount(void) const {
+    return mFileSuffixVector.size();
+}
+
+status_t DrmSupportInfo::addMimeType(const String8& mimeType) {
+    mMimeTypeVector.push(mimeType);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmSupportInfo::addFileSuffix(const String8& fileSuffix) {
+    mFileSuffixVector.push(fileSuffix);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmSupportInfo::setDescription(const String8& description) {
+    mDescription = description;
+    return DRM_NO_ERROR;
+}
+
+String8 DrmSupportInfo::getDescription() const {
+    return mDescription;
+}
+
+DrmSupportInfo::FileSuffixIterator DrmSupportInfo::getFileSuffixIterator() {
+    return FileSuffixIterator(this);
+}
+
+DrmSupportInfo::MimeTypeIterator DrmSupportInfo::getMimeTypeIterator() {
+    return MimeTypeIterator(this);
+}
+
+DrmSupportInfo::FileSuffixIterator::FileSuffixIterator(
+    const DrmSupportInfo::FileSuffixIterator& iterator) :
+    mDrmSupportInfo(iterator.mDrmSupportInfo),
+    mIndex(iterator.mIndex) {
+
+}
+
+DrmSupportInfo::FileSuffixIterator& DrmSupportInfo::FileSuffixIterator::operator=(
+    const DrmSupportInfo::FileSuffixIterator& iterator) {
+    mDrmSupportInfo = iterator.mDrmSupportInfo;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool DrmSupportInfo::FileSuffixIterator::hasNext() {
+    return mIndex < mDrmSupportInfo->mFileSuffixVector.size();
+}
+
+String8& DrmSupportInfo::FileSuffixIterator::next() {
+    String8& value = mDrmSupportInfo->mFileSuffixVector.editItemAt(mIndex);
+    mIndex++;
+    return value;
+}
+
+DrmSupportInfo::MimeTypeIterator::MimeTypeIterator(
+    const DrmSupportInfo::MimeTypeIterator& iterator) :
+    mDrmSupportInfo(iterator.mDrmSupportInfo),
+    mIndex(iterator.mIndex) {
+
+}
+
+DrmSupportInfo::MimeTypeIterator& DrmSupportInfo::MimeTypeIterator::operator=(
+    const DrmSupportInfo::MimeTypeIterator& iterator) {
+    mDrmSupportInfo = iterator.mDrmSupportInfo;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool DrmSupportInfo::MimeTypeIterator::hasNext() {
+    return mIndex < mDrmSupportInfo->mMimeTypeVector.size();
+}
+
+String8& DrmSupportInfo::MimeTypeIterator::next() {
+    String8& value = mDrmSupportInfo->mMimeTypeVector.editItemAt(mIndex);
+    mIndex++;
+    return value;
+}
+
diff --git a/drm/common/IDrmIOService.cpp b/drm/common/IDrmIOService.cpp
new file mode 100644
index 0000000..e44ca55
--- /dev/null
+++ b/drm/common/IDrmIOService.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <drm/drm_framework_common.h>
+#include "IDrmIOService.h"
+
+using namespace android;
+
+void BpDrmIOService::writeToFile(const String8& filePath, const String8& dataBuffer) {
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmIOService::getInterfaceDescriptor());
+    data.writeString8(filePath);
+    data.writeString8(dataBuffer);
+
+    remote()->transact(WRITE_TO_FILE, data, &reply);
+}
+
+String8 BpDrmIOService::readFromFile(const String8& filePath) {
+
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmIOService::getInterfaceDescriptor());
+    data.writeString8(filePath);
+
+    remote()->transact(READ_FROM_FILE, data, &reply);
+    return reply.readString8();
+}
+
+IMPLEMENT_META_INTERFACE(DrmIOService, "drm.IDrmIOService");
+
+status_t BnDrmIOService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+
+    switch (code) {
+    case WRITE_TO_FILE:
+    {
+        CHECK_INTERFACE(IDrmIOService, data, reply);
+
+        writeToFile(data.readString8(), data.readString8());
+        return DRM_NO_ERROR;
+    }
+
+    case READ_FROM_FILE:
+    {
+        CHECK_INTERFACE(IDrmIOService, data, reply);
+
+        String8 dataBuffer = readFromFile(data.readString8());
+        reply->writeString8(dataBuffer);
+        return DRM_NO_ERROR;
+    }
+
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
new file mode 100644
index 0000000..c28527c
--- /dev/null
+++ b/drm/common/IDrmManagerService.cpp
@@ -0,0 +1,1422 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IDrmManagerService(Native)"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/IPCThreadState.h>
+
+#include <drm/DrmInfo.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmRights.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmConvertedStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+
+#include "IDrmManagerService.h"
+
+#define INVALID_BUFFER_LENGTH -1
+
+using namespace android;
+
+int BpDrmManagerService::addUniqueId(int uniqueId) {
+    LOGV("add uniqueid");
+    Parcel data, reply;
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    remote()->transact(ADD_UNIQUEID, data, &reply);
+    return reply.readInt32();
+}
+
+void BpDrmManagerService::removeUniqueId(int uniqueId) {
+    LOGV("remove uniqueid");
+    Parcel data, reply;
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    remote()->transact(REMOVE_UNIQUEID, data, &reply);
+}
+
+status_t BpDrmManagerService::loadPlugIns(int uniqueId) {
+    LOGV("load plugins");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    remote()->transact(LOAD_PLUGINS, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::loadPlugIns(int uniqueId, const String8& plugInDirPath) {
+    LOGV("load plugins from path");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(plugInDirPath);
+
+    remote()->transact(LOAD_PLUGINS_FROM_PATH, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
+    LOGV("setDrmServiceListener");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeStrongBinder(drmServiceListener->asBinder());
+    remote()->transact(SET_DRM_SERVICE_LISTENER, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::unloadPlugIns(int uniqueId) {
+    LOGV("unload plugins");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    remote()->transact(UNLOAD_PLUGINS, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::installDrmEngine(int uniqueId, const String8& drmEngineFile) {
+    LOGV("Install DRM Engine");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(drmEngineFile);
+
+    remote()->transact(INSTALL_DRM_ENGINE, data, &reply);
+    return reply.readInt32();
+}
+
+DrmConstraints* BpDrmManagerService::getConstraints(
+            int uniqueId, const String8* path, const int action) {
+    LOGV("Get Constraints");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(*path);
+    data.writeInt32(action);
+
+    remote()->transact(GET_CONSTRAINTS_FROM_CONTENT, data, &reply);
+
+    DrmConstraints* drmConstraints = NULL;
+    if (0 != reply.dataAvail()) {
+        //Filling Drm Constraints
+        drmConstraints = new DrmConstraints();
+
+        const int size = reply.readInt32();
+        for (int index = 0; index < size; ++index) {
+            const String8 key(reply.readString8());
+            const int bufferSize = reply.readInt32();
+            char* data = NULL;
+            if (0 < bufferSize) {
+                data = new char[bufferSize];
+                reply.read(data, bufferSize);
+            }
+            drmConstraints->put(&key, data);
+        }
+    }
+    return drmConstraints;
+}
+
+bool BpDrmManagerService::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+    LOGV("Can Handle");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeString8(path);
+    data.writeString8(mimeType);
+
+    remote()->transact(CAN_HANDLE, data, &reply);
+
+    return static_cast<bool>(reply.readInt32());
+}
+
+DrmInfoStatus* BpDrmManagerService::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    LOGV("Process DRM Info");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    //Filling DRM info
+    data.writeInt32(drmInfo->getInfoType());
+    const DrmBuffer dataBuffer = drmInfo->getData();
+    const int dataBufferSize = dataBuffer.length;
+    data.writeInt32(dataBufferSize);
+    if (0 < dataBufferSize) {
+        data.write(dataBuffer.data, dataBufferSize);
+    }
+    data.writeString8(drmInfo->getMimeType());
+
+    data.writeInt32(drmInfo->getCount());
+    DrmInfo::KeyIterator keyIt = drmInfo->keyIterator();
+
+    while (keyIt.hasNext()) {
+        const String8 key = keyIt.next();
+        data.writeString8(key);
+        const String8 value = drmInfo->get(key);
+        data.writeString8((value == String8("")) ? String8("NULL") : value);
+    }
+
+    remote()->transact(PROCESS_DRM_INFO, data, &reply);
+
+    DrmInfoStatus* drmInfoStatus = NULL;
+    if (0 != reply.dataAvail()) {
+        //Filling DRM Info Status
+        const int statusCode = reply.readInt32();
+        const String8 mimeType = reply.readString8();
+
+        DrmBuffer* drmBuffer = NULL;
+        if (0 != reply.dataAvail()) {
+            const int bufferSize = reply.readInt32();
+            char* data = NULL;
+            if (0 < bufferSize) {
+                data = new char[bufferSize];
+                reply.read(data, bufferSize);
+            }
+            drmBuffer = new DrmBuffer(data, bufferSize);
+        }
+        drmInfoStatus = new DrmInfoStatus(statusCode, drmBuffer, mimeType);
+    }
+    return drmInfoStatus;
+}
+
+DrmInfo* BpDrmManagerService::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest) {
+    LOGV("Acquire DRM Info");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    //Filling DRM Info Request
+    data.writeInt32(drmInforequest->getInfoType());
+    data.writeString8(drmInforequest->getMimeType());
+
+    data.writeInt32(drmInforequest->getCount());
+    DrmInfoRequest::KeyIterator keyIt = drmInforequest->keyIterator();
+
+    while (keyIt.hasNext()) {
+        const String8 key = keyIt.next();
+        data.writeString8(key);
+        const String8 value = drmInforequest->get(key);
+        data.writeString8((value == String8("")) ? String8("NULL") : value);
+    }
+
+    remote()->transact(ACQUIRE_DRM_INFO, data, &reply);
+
+    DrmInfo* drmInfo = NULL;
+    if (0 != reply.dataAvail()) {
+        //Filling DRM Info
+        const int infoType = reply.readInt32();
+        const int bufferSize = reply.readInt32();
+        char* data = NULL;
+
+        if (0 < bufferSize) {
+            data = new char[bufferSize];
+            reply.read(data, bufferSize);
+        }
+        drmInfo = new DrmInfo(infoType, DrmBuffer(data, bufferSize), reply.readString8());
+
+        const int size = reply.readInt32();
+        for (int index = 0; index < size; ++index) {
+            const String8 key(reply.readString8());
+            const String8 value(reply.readString8());
+            drmInfo->put(key, (value == String8("NULL")) ? String8("") : value);
+        }
+    }
+    return drmInfo;
+}
+
+status_t BpDrmManagerService::saveRights(
+            int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    LOGV("Save Rights");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    //Filling Drm Rights
+    const DrmBuffer dataBuffer = drmRights.getData();
+    data.writeInt32(dataBuffer.length);
+    data.write(dataBuffer.data, dataBuffer.length);
+
+    const String8 mimeType = drmRights.getMimeType();
+    data.writeString8((mimeType == String8("")) ? String8("NULL") : mimeType);
+
+    const String8 accountId = drmRights.getAccountId();
+    data.writeString8((accountId == String8("")) ? String8("NULL") : accountId);
+
+    const String8 subscriptionId = drmRights.getSubscriptionId();
+    data.writeString8((subscriptionId == String8("")) ? String8("NULL") : subscriptionId);
+
+    data.writeString8((rightsPath == String8("")) ? String8("NULL") : rightsPath);
+    data.writeString8((contentPath == String8("")) ? String8("NULL") : contentPath);
+
+    remote()->transact(SAVE_RIGHTS, data, &reply);
+    return reply.readInt32();
+}
+
+String8 BpDrmManagerService::getOriginalMimeType(int uniqueId, const String8& path) {
+    LOGV("Get Original MimeType");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(path);
+
+    remote()->transact(GET_ORIGINAL_MIMETYPE, data, &reply);
+    return reply.readString8();
+}
+
+int BpDrmManagerService::getDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) {
+    LOGV("Get Drm object type");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(path);
+    data.writeString8(mimeType);
+
+    remote()->transact(GET_DRM_OBJECT_TYPE, data, &reply);
+
+    return reply.readInt32();
+}
+
+int BpDrmManagerService::checkRightsStatus(int uniqueId, const String8& path, int action) {
+    LOGV("checkRightsStatus");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(path);
+    data.writeInt32(action);
+
+    remote()->transact(CHECK_RIGHTS_STATUS, data, &reply);
+
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    LOGV("consumeRights");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+
+    data.writeInt32(action);
+    data.writeInt32(static_cast< int>(reserve));
+
+    remote()->transact(CONSUME_RIGHTS, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    LOGV("setPlaybackStatus");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+
+    data.writeInt32(playbackStatus);
+    data.writeInt32(position);
+
+    remote()->transact(SET_PLAYBACK_STATUS, data, &reply);
+    return reply.readInt32();
+}
+
+bool BpDrmManagerService::validateAction(
+            int uniqueId, const String8& path,
+            int action, const ActionDescription& description) {
+    LOGV("validateAction");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(path);
+    data.writeInt32(action);
+    data.writeInt32(description.outputType);
+    data.writeInt32(description.configuration);
+
+    remote()->transact(VALIDATE_ACTION, data, &reply);
+
+    return static_cast<bool>(reply.readInt32());
+}
+
+status_t BpDrmManagerService::removeRights(int uniqueId, const String8& path) {
+    LOGV("removeRights");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(path);
+
+    remote()->transact(REMOVE_RIGHTS, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::removeAllRights(int uniqueId) {
+    LOGV("removeAllRights");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    remote()->transact(REMOVE_ALL_RIGHTS, data, &reply);
+    return reply.readInt32();
+}
+
+int BpDrmManagerService::openConvertSession(int uniqueId, const String8& mimeType) {
+    LOGV("openConvertSession");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeString8(mimeType);
+
+    remote()->transact(OPEN_CONVERT_SESSION, data, &reply);
+    return reply.readInt32();
+}
+
+DrmConvertedStatus* BpDrmManagerService::convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) {
+    LOGV("convertData");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeInt32(convertId);
+    data.writeInt32(inputData->length);
+    data.write(inputData->data, inputData->length);
+
+    remote()->transact(CONVERT_DATA, data, &reply);
+
+    DrmConvertedStatus* drmConvertedStatus = NULL;
+
+    if (0 != reply.dataAvail()) {
+        //Filling DRM Converted Status
+        const int statusCode = reply.readInt32();
+        const int offset = reply.readInt32();
+
+        DrmBuffer* convertedData = NULL;
+        if (0 != reply.dataAvail()) {
+            const int bufferSize = reply.readInt32();
+            char* data = NULL;
+            if (0 < bufferSize) {
+                data = new char[bufferSize];
+                reply.read(data, bufferSize);
+            }
+            convertedData = new DrmBuffer(data, bufferSize);
+        }
+        drmConvertedStatus = new DrmConvertedStatus(statusCode, convertedData, offset);
+    }
+    return drmConvertedStatus;
+}
+
+DrmConvertedStatus* BpDrmManagerService::closeConvertSession(int uniqueId, int convertId) {
+    LOGV("closeConvertSession");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+    data.writeInt32(convertId);
+
+    remote()->transact(CLOSE_CONVERT_SESSION, data, &reply);
+
+    DrmConvertedStatus* drmConvertedStatus = NULL;
+
+    if (0 != reply.dataAvail()) {
+        //Filling DRM Converted Status
+        const int statusCode = reply.readInt32();
+        const int offset = reply.readInt32();
+
+        DrmBuffer* convertedData = NULL;
+        if (0 != reply.dataAvail()) {
+            const int bufferSize = reply.readInt32();
+            char* data = NULL;
+            if (0 < bufferSize) {
+                data = new char[bufferSize];
+                reply.read(data, bufferSize);
+            }
+            convertedData = new DrmBuffer(data, bufferSize);
+        }
+        drmConvertedStatus = new DrmConvertedStatus(statusCode, convertedData, offset);
+    }
+    return drmConvertedStatus;
+}
+
+status_t BpDrmManagerService::getAllSupportInfo(
+            int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+    LOGV("Get All Support Info");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    remote()->transact(GET_ALL_SUPPORT_INFO, data, &reply);
+
+    //Filling DRM Support Info
+    const int arraySize = reply.readInt32();
+    if (0 < arraySize) {
+        *drmSupportInfoArray = new DrmSupportInfo[arraySize];
+
+        for (int index = 0; index < arraySize; ++index) {
+            DrmSupportInfo drmSupportInfo;
+
+            const int fileSuffixVectorSize = reply.readInt32();
+            for (int i = 0; i < fileSuffixVectorSize; ++i) {
+                drmSupportInfo.addFileSuffix(reply.readString8());
+            }
+
+            const int mimeTypeVectorSize = reply.readInt32();
+            for (int i = 0; i < mimeTypeVectorSize; ++i) {
+                drmSupportInfo.addMimeType(reply.readString8());
+            }
+
+            drmSupportInfo.setDescription(reply.readString8());
+            (*drmSupportInfoArray)[index] = drmSupportInfo;
+        }
+    }
+    *length = arraySize;
+    return reply.readInt32();
+}
+
+DecryptHandle* BpDrmManagerService::openDecryptSession(
+            int uniqueId, int fd, int offset, int length) {
+    LOGV("Entering BpDrmManagerService::openDecryptSession");
+    Parcel data, reply;
+
+    const String16 interfaceDescriptor = IDrmManagerService::getInterfaceDescriptor();
+    data.writeInterfaceToken(interfaceDescriptor);
+    data.writeInt32(uniqueId);
+    data.writeFileDescriptor(fd);
+    data.writeInt32(offset);
+    data.writeInt32(length);
+
+    remote()->transact(OPEN_DECRYPT_SESSION, data, &reply);
+
+    DecryptHandle* handle = NULL;
+    if (0 != reply.dataAvail()) {
+        handle = new DecryptHandle();
+        handle->decryptId = reply.readInt32();
+        handle->mimeType = reply.readString8();
+        handle->decryptApiType = reply.readInt32();
+        handle->status = reply.readInt32();
+        handle->decryptInfo = NULL;
+        if (0 != reply.dataAvail()) {
+            handle->decryptInfo = new DecryptInfo();
+            handle->decryptInfo->decryptBufferLength = reply.readInt32();
+        }
+    } else {
+        LOGE("no decryptHandle is generated in service side");
+    }
+    return handle;
+}
+
+status_t BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    LOGV("closeDecryptSession");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+
+    remote()->transact(CLOSE_DECRYPT_SESSION, data, &reply);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        LOGV("deleting decryptInfo");
+        delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
+    }
+    delete decryptHandle; decryptHandle = NULL;
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::initializeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    LOGV("initializeDecryptUnit");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+    data.writeInt32(decryptUnitId);
+
+    data.writeInt32(headerInfo->length);
+    data.write(headerInfo->data, headerInfo->length);
+
+    remote()->transact(INITIALIZE_DECRYPT_UNIT, data, &reply);
+    return reply.readInt32();
+}
+
+status_t BpDrmManagerService::decrypt(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    LOGV("decrypt");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+
+    data.writeInt32(decryptUnitId);
+    data.writeInt32((*decBuffer)->length);
+
+    data.writeInt32(encBuffer->length);
+    data.write(encBuffer->data, encBuffer->length);
+
+    if (NULL != IV) {
+        data.writeInt32(IV->length);
+        data.write(IV->data, IV->length);
+    }
+
+    remote()->transact(DECRYPT, data, &reply);
+
+    const status_t status = reply.readInt32();
+    LOGV("Return value of decrypt() is %d", status);
+
+    const int size = reply.readInt32();
+    (*decBuffer)->length = size;
+    reply.read((void *)(*decBuffer)->data, size);
+
+    return status;
+}
+
+status_t BpDrmManagerService::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    LOGV("finalizeDecryptUnit");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+
+    data.writeInt32(decryptUnitId);
+
+    remote()->transact(FINALIZE_DECRYPT_UNIT, data, &reply);
+    return reply.readInt32();
+}
+
+ssize_t BpDrmManagerService::pread(
+            int uniqueId, DecryptHandle* decryptHandle, void* buffer,
+            ssize_t numBytes, off_t offset) {
+    LOGV("read");
+    Parcel data, reply;
+    int result;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    data.writeInt32(decryptHandle->decryptId);
+    data.writeString8(decryptHandle->mimeType);
+    data.writeInt32(decryptHandle->decryptApiType);
+    data.writeInt32(decryptHandle->status);
+
+    if (NULL != decryptHandle->decryptInfo) {
+        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
+    } else {
+        data.writeInt32(INVALID_BUFFER_LENGTH);
+    }
+
+    data.writeInt32(numBytes);
+    data.writeInt32(offset);
+
+    remote()->transact(PREAD, data, &reply);
+    result = reply.readInt32();
+    if (0 < result) {
+        reply.read(buffer, result);
+    }
+    return result;
+}
+
+IMPLEMENT_META_INTERFACE(DrmManagerService, "drm.IDrmManagerService");
+
+status_t BnDrmManagerService::onTransact(
+            uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags) {
+    LOGV("Entering BnDrmManagerService::onTransact with code %d", code);
+
+    switch (code) {
+    case ADD_UNIQUEID:
+    {
+        LOGV("BnDrmManagerService::onTransact :ADD_UNIQUEID");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+        int uniqueId = addUniqueId(data.readInt32());
+        reply->writeInt32(uniqueId);
+        return DRM_NO_ERROR;
+    }
+
+    case REMOVE_UNIQUEID:
+    {
+        LOGV("BnDrmManagerService::onTransact :REMOVE_UNIQUEID");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+        removeUniqueId(data.readInt32());
+        return DRM_NO_ERROR;
+    }
+
+    case LOAD_PLUGINS:
+    {
+        LOGV("BnDrmManagerService::onTransact :LOAD_PLUGINS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        status_t status = loadPlugIns(data.readInt32());
+
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case LOAD_PLUGINS_FROM_PATH:
+    {
+        LOGV("BnDrmManagerService::onTransact :LOAD_PLUGINS_FROM_PATH");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        status_t status = loadPlugIns(data.readInt32(), data.readString8());
+
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case SET_DRM_SERVICE_LISTENER:
+    {
+        LOGV("BnDrmManagerService::onTransact :SET_DRM_SERVICE_LISTENER");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        const sp<IDrmServiceListener> drmServiceListener
+            = interface_cast<IDrmServiceListener> (data.readStrongBinder());
+
+        status_t status = setDrmServiceListener(uniqueId, drmServiceListener);
+
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case UNLOAD_PLUGINS:
+    {
+        LOGV("BnDrmManagerService::onTransact :UNLOAD_PLUGINS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        status_t status = unloadPlugIns(uniqueId);
+
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case INSTALL_DRM_ENGINE:
+    {
+        LOGV("BnDrmManagerService::onTransact :INSTALL_DRM_ENGINE");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        status_t status = installDrmEngine(data.readInt32(), data.readString8());
+
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case GET_CONSTRAINTS_FROM_CONTENT:
+    {
+        LOGV("BnDrmManagerService::onTransact :GET_CONSTRAINTS_FROM_CONTENT");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        const String8 path = data.readString8();
+
+        DrmConstraints* drmConstraints = getConstraints(uniqueId, &path, data.readInt32());
+
+        if (NULL != drmConstraints) {
+            //Filling DRM Constraints contents
+            reply->writeInt32(drmConstraints->getCount());
+
+            DrmConstraints::KeyIterator keyIt = drmConstraints->keyIterator();
+            while (keyIt.hasNext()) {
+                const String8 key = keyIt.next();
+                reply->writeString8(key);
+                const char* value = drmConstraints->getAsByteArray(&key);
+                int bufferSize = 0;
+                if (NULL != value) {
+                    bufferSize = strlen(value);
+                }
+                reply->writeInt32(bufferSize + 1);
+                reply->write(value, bufferSize + 1);
+            }
+        }
+        delete drmConstraints; drmConstraints = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case CAN_HANDLE:
+    {
+        LOGV("BnDrmManagerService::onTransact :CAN_HANDLE");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        const String8 path = data.readString8();
+        const String8 mimeType = data.readString8();
+
+        bool result = canHandle(uniqueId, path, mimeType);
+
+        reply->writeInt32(result);
+        return DRM_NO_ERROR;
+    }
+
+    case PROCESS_DRM_INFO:
+    {
+        LOGV("BnDrmManagerService::onTransact :PROCESS_DRM_INFO");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        //Filling DRM info
+        const int infoType = data.readInt32();
+        const int bufferSize = data.readInt32();
+        char* buffer = NULL;
+        if (0 < bufferSize) {
+            buffer = (char *)data.readInplace(bufferSize);
+        }
+        const DrmBuffer drmBuffer(buffer, bufferSize);
+        DrmInfo* drmInfo = new DrmInfo(infoType, drmBuffer, data.readString8());
+
+        const int size = data.readInt32();
+        for (int index = 0; index < size; ++index) {
+            const String8 key(data.readString8());
+            const String8 value(data.readString8());
+            drmInfo->put(key, (value == String8("NULL")) ? String8("") : value);
+        }
+
+        DrmInfoStatus* drmInfoStatus = processDrmInfo(uniqueId, drmInfo);
+
+        if (NULL != drmInfoStatus) {
+            //Filling DRM Info Status contents
+            reply->writeInt32(drmInfoStatus->statusCode);
+            reply->writeString8(drmInfoStatus->mimeType);
+
+            if (NULL != drmInfoStatus->drmBuffer) {
+                const DrmBuffer* drmBuffer = drmInfoStatus->drmBuffer;
+                const int bufferSize = drmBuffer->length;
+                reply->writeInt32(bufferSize);
+                if (0 < bufferSize) {
+                    reply->write(drmBuffer->data, bufferSize);
+                }
+                delete [] drmBuffer->data;
+                delete drmBuffer; drmBuffer = NULL;
+            }
+        }
+        delete drmInfo; drmInfo = NULL;
+        delete drmInfoStatus; drmInfoStatus = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case ACQUIRE_DRM_INFO:
+    {
+        LOGV("BnDrmManagerService::onTransact :ACQUIRE_DRM_INFO");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        //Filling DRM info Request
+        DrmInfoRequest* drmInfoRequest = new DrmInfoRequest(data.readInt32(), data.readString8());
+
+        const int size = data.readInt32();
+        for (int index = 0; index < size; ++index) {
+            const String8 key(data.readString8());
+            const String8 value(data.readString8());
+            drmInfoRequest->put(key, (value == String8("NULL")) ? String8("") : value);
+        }
+
+        DrmInfo* drmInfo = acquireDrmInfo(uniqueId, drmInfoRequest);
+
+        if (NULL != drmInfo) {
+            //Filling DRM Info
+            const DrmBuffer drmBuffer = drmInfo->getData();
+            reply->writeInt32(drmInfo->getInfoType());
+
+            const int bufferSize = drmBuffer.length;
+            reply->writeInt32(bufferSize);
+            if (0 < bufferSize) {
+                reply->write(drmBuffer.data, bufferSize);
+            }
+            reply->writeString8(drmInfo->getMimeType());
+            reply->writeInt32(drmInfo->getCount());
+
+            DrmInfo::KeyIterator keyIt = drmInfo->keyIterator();
+            while (keyIt.hasNext()) {
+                const String8 key = keyIt.next();
+                reply->writeString8(key);
+                const String8 value = drmInfo->get(key);
+                reply->writeString8((value == String8("")) ? String8("NULL") : value);
+            }
+            delete [] drmBuffer.data;
+        }
+        delete drmInfoRequest; drmInfoRequest = NULL;
+        delete drmInfo; drmInfo = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case SAVE_RIGHTS:
+    {
+        LOGV("BnDrmManagerService::onTransact :SAVE_RIGHTS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        //Filling DRM Rights
+        const int bufferSize = data.readInt32();
+        const DrmBuffer drmBuffer((char *)data.readInplace(bufferSize), bufferSize);
+
+        const String8 mimeType(data.readString8());
+        const String8 accountId(data.readString8());
+        const String8 subscriptionId(data.readString8());
+        const String8 rightsPath(data.readString8());
+        const String8 contentPath(data.readString8());
+
+        DrmRights drmRights(drmBuffer,
+                            ((mimeType == String8("NULL")) ? String8("") : mimeType),
+                            ((accountId == String8("NULL")) ? String8("") : accountId),
+                            ((subscriptionId == String8("NULL")) ? String8("") : subscriptionId));
+
+        const status_t status = saveRights(uniqueId, drmRights,
+                            ((rightsPath == String8("NULL")) ? String8("") : rightsPath),
+                            ((contentPath == String8("NULL")) ? String8("") : contentPath));
+
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case GET_ORIGINAL_MIMETYPE:
+    {
+        LOGV("BnDrmManagerService::onTransact :GET_ORIGINAL_MIMETYPE");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const String8 originalMimeType = getOriginalMimeType(data.readInt32(), data.readString8());
+
+        reply->writeString8(originalMimeType);
+        return DRM_NO_ERROR;
+    }
+
+    case GET_DRM_OBJECT_TYPE:
+    {
+        LOGV("BnDrmManagerService::onTransact :GET_DRM_OBJECT_TYPE");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int drmObjectType
+            = getDrmObjectType(data.readInt32(), data.readString8(), data.readString8());
+
+        reply->writeInt32(drmObjectType);
+        return DRM_NO_ERROR;
+    }
+
+    case CHECK_RIGHTS_STATUS:
+    {
+        LOGV("BnDrmManagerService::onTransact :CHECK_RIGHTS_STATUS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int result
+            = checkRightsStatus(data.readInt32(), data.readString8(), data.readInt32());
+
+        reply->writeInt32(result);
+        return DRM_NO_ERROR;
+    }
+
+    case CONSUME_RIGHTS:
+    {
+        LOGV("BnDrmManagerService::onTransact :CONSUME_RIGHTS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle handle;
+        handle.decryptId = data.readInt32();
+        handle.mimeType = data.readString8();
+        handle.decryptApiType = data.readInt32();
+        handle.status = data.readInt32();
+        handle.decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle.decryptInfo = new DecryptInfo();
+            handle.decryptInfo->decryptBufferLength = bufferLength;
+        }
+
+        const status_t status
+            = consumeRights(uniqueId, &handle, data.readInt32(),
+                static_cast<bool>(data.readInt32()));
+        reply->writeInt32(status);
+
+        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case SET_PLAYBACK_STATUS:
+    {
+        LOGV("BnDrmManagerService::onTransact :SET_PLAYBACK_STATUS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle handle;
+        handle.decryptId = data.readInt32();
+        handle.mimeType = data.readString8();
+        handle.decryptApiType = data.readInt32();
+        handle.status = data.readInt32();
+        handle.decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle.decryptInfo = new DecryptInfo();
+            handle.decryptInfo->decryptBufferLength = bufferLength;
+        }
+
+        const status_t status
+            = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+        reply->writeInt32(status);
+
+        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case VALIDATE_ACTION:
+    {
+        LOGV("BnDrmManagerService::onTransact :VALIDATE_ACTION");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        bool result = validateAction(
+                                data.readInt32(),
+                                data.readString8(),
+                                data.readInt32(),
+                                ActionDescription(data.readInt32(), data.readInt32()));
+
+        reply->writeInt32(result);
+        return DRM_NO_ERROR;
+    }
+
+    case REMOVE_RIGHTS:
+    {
+        LOGV("BnDrmManagerService::onTransact :REMOVE_RIGHTS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const status_t status = removeRights(data.readInt32(), data.readString8());
+        reply->writeInt32(status);
+
+        return DRM_NO_ERROR;
+    }
+
+    case REMOVE_ALL_RIGHTS:
+    {
+        LOGV("BnDrmManagerService::onTransact :REMOVE_ALL_RIGHTS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const status_t status = removeAllRights(data.readInt32());
+        reply->writeInt32(status);
+
+        return DRM_NO_ERROR;
+    }
+
+    case OPEN_CONVERT_SESSION:
+    {
+        LOGV("BnDrmManagerService::onTransact :OPEN_CONVERT_SESSION");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int convertId = openConvertSession(data.readInt32(), data.readString8());
+
+        reply->writeInt32(convertId);
+        return DRM_NO_ERROR;
+    }
+
+    case CONVERT_DATA:
+    {
+        LOGV("BnDrmManagerService::onTransact :CONVERT_DATA");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        const int convertId = data.readInt32();
+
+        //Filling input data
+        const int bufferSize = data.readInt32();
+        DrmBuffer* inputData = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);
+
+        DrmConvertedStatus*    drmConvertedStatus = convertData(uniqueId, convertId, inputData);
+
+        if (NULL != drmConvertedStatus) {
+            //Filling Drm Converted Ststus
+            reply->writeInt32(drmConvertedStatus->statusCode);
+            reply->writeInt32(drmConvertedStatus->offset);
+
+            if (NULL != drmConvertedStatus->convertedData) {
+                const DrmBuffer* convertedData = drmConvertedStatus->convertedData;
+                const int bufferSize = convertedData->length;
+                reply->writeInt32(bufferSize);
+                if (0 < bufferSize) {
+                    reply->write(convertedData->data, bufferSize);
+                }
+                delete [] convertedData->data;
+                delete convertedData; convertedData = NULL;
+            }
+        }
+        delete inputData; inputData = NULL;
+        delete drmConvertedStatus; drmConvertedStatus = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case CLOSE_CONVERT_SESSION:
+    {
+        LOGV("BnDrmManagerService::onTransact :CLOSE_CONVERT_SESSION");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        DrmConvertedStatus*    drmConvertedStatus
+            = closeConvertSession(data.readInt32(), data.readInt32());
+
+        if (NULL != drmConvertedStatus) {
+            //Filling Drm Converted Ststus
+            reply->writeInt32(drmConvertedStatus->statusCode);
+            reply->writeInt32(drmConvertedStatus->offset);
+
+            if (NULL != drmConvertedStatus->convertedData) {
+                const DrmBuffer* convertedData = drmConvertedStatus->convertedData;
+                const int bufferSize = convertedData->length;
+                reply->writeInt32(bufferSize);
+                if (0 < bufferSize) {
+                    reply->write(convertedData->data, bufferSize);
+                }
+                delete [] convertedData->data;
+                delete convertedData; convertedData = NULL;
+            }
+        }
+        delete drmConvertedStatus; drmConvertedStatus = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case GET_ALL_SUPPORT_INFO:
+    {
+        LOGV("BnDrmManagerService::onTransact :GET_ALL_SUPPORT_INFO");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        int length = 0;
+        DrmSupportInfo* drmSupportInfoArray = NULL;
+
+        status_t status = getAllSupportInfo(uniqueId, &length, &drmSupportInfoArray);
+
+        reply->writeInt32(length);
+        for (int i = 0; i < length; ++i) {
+            DrmSupportInfo drmSupportInfo = drmSupportInfoArray[i];
+
+            reply->writeInt32(drmSupportInfo.getFileSuffixCount());
+            DrmSupportInfo::FileSuffixIterator fileSuffixIt
+                = drmSupportInfo.getFileSuffixIterator();
+            while (fileSuffixIt.hasNext()) {
+                reply->writeString8(fileSuffixIt.next());
+            }
+
+            reply->writeInt32(drmSupportInfo.getMimeTypeCount());
+            DrmSupportInfo::MimeTypeIterator mimeTypeIt = drmSupportInfo.getMimeTypeIterator();
+            while (mimeTypeIt.hasNext()) {
+                reply->writeString8(mimeTypeIt.next());
+            }
+            reply->writeString8(drmSupportInfo.getDescription());
+        }
+        delete [] drmSupportInfoArray; drmSupportInfoArray = NULL;
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case OPEN_DECRYPT_SESSION:
+    {
+        LOGV("BnDrmManagerService::onTransact :OPEN_DECRYPT_SESSION");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        const int fd = data.readFileDescriptor();
+
+        DecryptHandle* handle
+            = openDecryptSession(uniqueId, fd, data.readInt32(), data.readInt32());
+
+        if (NULL != handle) {
+            reply->writeInt32(handle->decryptId);
+            reply->writeString8(handle->mimeType);
+            reply->writeInt32(handle->decryptApiType);
+            reply->writeInt32(handle->status);
+            if (NULL != handle->decryptInfo) {
+                reply->writeInt32(handle->decryptInfo->decryptBufferLength);
+                delete handle->decryptInfo; handle->decryptInfo = NULL;
+            }
+        } else {
+            LOGE("NULL decryptHandle is returned");
+        }
+        delete handle; handle = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case CLOSE_DECRYPT_SESSION:
+    {
+        LOGV("BnDrmManagerService::onTransact :CLOSE_DECRYPT_SESSION");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle* handle = new DecryptHandle();
+        handle->decryptId = data.readInt32();
+        handle->mimeType = data.readString8();
+        handle->decryptApiType = data.readInt32();
+        handle->status = data.readInt32();
+        handle->decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle->decryptInfo = new DecryptInfo();
+            handle->decryptInfo->decryptBufferLength = bufferLength;
+        }
+
+        const status_t status = closeDecryptSession(uniqueId, handle);
+        reply->writeInt32(status);
+        return DRM_NO_ERROR;
+    }
+
+    case INITIALIZE_DECRYPT_UNIT:
+    {
+        LOGV("BnDrmManagerService::onTransact :INITIALIZE_DECRYPT_UNIT");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle handle;
+        handle.decryptId = data.readInt32();
+        handle.mimeType = data.readString8();
+        handle.decryptApiType = data.readInt32();
+        handle.status = data.readInt32();
+        handle.decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle.decryptInfo = new DecryptInfo();
+            handle.decryptInfo->decryptBufferLength = bufferLength;
+        }
+        const int decryptUnitId = data.readInt32();
+
+        //Filling Header info
+        const int bufferSize = data.readInt32();
+        DrmBuffer* headerInfo = NULL;
+        headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);
+
+        const status_t status
+            = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+        reply->writeInt32(status);
+
+        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        delete headerInfo; headerInfo = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case DECRYPT:
+    {
+        LOGV("BnDrmManagerService::onTransact :DECRYPT");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle handle;
+        handle.decryptId = data.readInt32();
+        handle.mimeType = data.readString8();
+        handle.decryptApiType = data.readInt32();
+        handle.status = data.readInt32();
+        handle.decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle.decryptInfo = new DecryptInfo();
+            handle.decryptInfo->decryptBufferLength = bufferLength;
+        }
+        const int decryptUnitId = data.readInt32();
+        const int decBufferSize = data.readInt32();
+
+        const int encBufferSize = data.readInt32();
+        DrmBuffer* encBuffer
+            = new DrmBuffer((char *)data.readInplace(encBufferSize), encBufferSize);
+
+        char* buffer = NULL;
+        buffer = new char[decBufferSize];
+        DrmBuffer* decBuffer = new DrmBuffer(buffer, decBufferSize);
+
+        DrmBuffer* IV = NULL;
+        if (0 != data.dataAvail()) {
+            const int ivBufferlength = data.readInt32();
+            IV = new DrmBuffer((char *)data.readInplace(ivBufferlength), ivBufferlength);
+        }
+
+        const status_t status
+            = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer, IV);
+
+        reply->writeInt32(status);
+
+        const int size = decBuffer->length;
+        reply->writeInt32(size);
+        reply->write(decBuffer->data, size);
+
+        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        delete encBuffer; encBuffer = NULL;
+        delete decBuffer; decBuffer = NULL;
+        delete [] buffer; buffer = NULL;
+        delete IV; IV = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case FINALIZE_DECRYPT_UNIT:
+    {
+        LOGV("BnDrmManagerService::onTransact :FINALIZE_DECRYPT_UNIT");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle handle;
+        handle.decryptId = data.readInt32();
+        handle.mimeType = data.readString8();
+        handle.decryptApiType = data.readInt32();
+        handle.status = data.readInt32();
+        handle.decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle.decryptInfo = new DecryptInfo();
+            handle.decryptInfo->decryptBufferLength = bufferLength;
+        }
+
+        const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+        reply->writeInt32(status);
+
+        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    case PREAD:
+    {
+        LOGV("BnDrmManagerService::onTransact :READ");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+
+        DecryptHandle handle;
+        handle.decryptId = data.readInt32();
+        handle.mimeType = data.readString8();
+        handle.decryptApiType = data.readInt32();
+        handle.status = data.readInt32();
+        handle.decryptInfo = NULL;
+
+        const int bufferLength = data.readInt32();
+        if (INVALID_BUFFER_LENGTH != bufferLength) {
+            handle.decryptInfo = new DecryptInfo();
+            handle.decryptInfo->decryptBufferLength = bufferLength;
+        }
+
+        const int numBytes = data.readInt32();
+        char* buffer = new char[numBytes];
+
+        const off_t offset = data.readInt32();
+
+        ssize_t result = pread(uniqueId, &handle, buffer, numBytes, offset);
+        reply->writeInt32(result);
+        if (0 < result) {
+            reply->write(buffer, result);
+        }
+
+        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        delete [] buffer, buffer = NULL;
+        return DRM_NO_ERROR;
+    }
+
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
diff --git a/drm/common/IDrmServiceListener.cpp b/drm/common/IDrmServiceListener.cpp
new file mode 100644
index 0000000..6eeea40
--- /dev/null
+++ b/drm/common/IDrmServiceListener.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <drm/drm_framework_common.h>
+#include <drm/DrmInfoEvent.h>
+#include "IDrmServiceListener.h"
+
+using namespace android;
+
+status_t BpDrmServiceListener::notify(const DrmInfoEvent& event) {
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmServiceListener::getInterfaceDescriptor());
+    data.writeInt32(event.getUniqueId());
+    data.writeInt32(event.getType());
+    data.writeString8(event.getMessage());
+
+    remote()->transact(NOTIFY, data, &reply);
+    return reply.readInt32();
+}
+
+IMPLEMENT_META_INTERFACE(DrmServiceListener, "drm.IDrmServiceListener");
+
+status_t BnDrmServiceListener::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+
+    switch (code) {
+    case NOTIFY:
+    {
+        CHECK_INTERFACE(IDrmServiceListener, data, reply);
+        int uniqueId = data.readInt32();
+        int type = data.readInt32();
+        const String8& message = data.readString8();
+
+        status_t status = notify(DrmInfoEvent(uniqueId, type, message));
+        reply->writeInt32(status);
+
+        return DRM_NO_ERROR;
+    }
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
diff --git a/drm/common/ReadWriteUtils.cpp b/drm/common/ReadWriteUtils.cpp
new file mode 100644
index 0000000..7ec4fa2
--- /dev/null
+++ b/drm/common/ReadWriteUtils.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ReadWriteUtils"
+#include <utils/Log.h>
+
+#include <ReadWriteUtils.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+using namespace android;
+
+#define FAILURE -1
+
+String8 ReadWriteUtils::readBytes(const String8& filePath) {
+    FILE* file = NULL;
+    file = fopen(filePath.string(), "r");
+
+    String8 string("");
+    if (NULL != file) {
+        int fd = fileno(file);
+        struct stat sb;
+
+        if (fstat(fd, &sb) == 0 && sb.st_size > 0) {
+            int length = sb.st_size;
+            char* bytes = new char[length];
+            if (length == read(fd, (void*) bytes, length)) {
+                string.append(bytes, length);
+            }
+            delete bytes;
+        }
+        fclose(file);
+    }
+    return string;
+}
+
+int ReadWriteUtils::readBytes(const String8& filePath, char** buffer) {
+    FILE* file = NULL;
+    file = fopen(filePath.string(), "r");
+    int length = 0;
+
+    if (NULL != file) {
+        int fd = fileno(file);
+        struct stat sb;
+
+        if (fstat(fd, &sb) == 0 && sb.st_size > 0) {
+            length = sb.st_size;
+            *buffer = new char[length];
+            if (length != read(fd, (void*) *buffer, length)) {
+                length = FAILURE;
+            }
+        }
+        fclose(file);
+    }
+    return length;
+}
+
+void ReadWriteUtils::writeToFile(const String8& filePath, const String8& data) {
+    FILE* file = NULL;
+    file = fopen(filePath.string(), "w+");
+
+    if (NULL != file) {
+        int fd = fileno(file);
+
+        int size = data.size();
+        if (FAILURE != ftruncate(fd, size)) {
+            if (size != write(fd, data.string(), size)) {
+                LOGE("Failed to write the data to: %s", filePath.string());
+            }
+        }
+        fclose(file);
+    }
+}
+
+void ReadWriteUtils::appendToFile(const String8& filePath, const String8& data) {
+    FILE* file = NULL;
+    file = fopen(filePath.string(), "a+");
+
+    if (NULL != file) {
+        int fd = fileno(file);
+
+        int size = data.size();
+        if (size != write(fd, data.string(), size)) {
+            LOGE("Failed to write the data to: %s", filePath.string());
+        }
+        fclose(file);
+    }
+}
+
diff --git a/drm/drmioserver/Android.mk b/drm/drmioserver/Android.mk
new file mode 100644
index 0000000..11571c7
--- /dev/null
+++ b/drm/drmioserver/Android.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    main_drmioserver.cpp \
+    DrmIOService.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    libbinder
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/include
+
+LOCAL_MODULE:= drmioserver
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/drm/drmioserver/DrmIOService.cpp b/drm/drmioserver/DrmIOService.cpp
new file mode 100644
index 0000000..60e6e70
--- /dev/null
+++ b/drm/drmioserver/DrmIOService.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmIOService"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include "DrmIOService.h"
+#include "ReadWriteUtils.h"
+
+using namespace android;
+
+void DrmIOService::instantiate() {
+    LOGV("instantiate");
+    defaultServiceManager()->addService(String16("drm.drmIOService"), new DrmIOService());
+}
+
+DrmIOService::DrmIOService() {
+    LOGV("created");
+}
+
+DrmIOService::~DrmIOService() {
+    LOGV("Destroyed");
+}
+
+void DrmIOService::writeToFile(const String8& filePath, const String8& dataBuffer) {
+    LOGV("Entering writeToFile");
+    ReadWriteUtils::writeToFile(filePath, dataBuffer);
+}
+
+String8 DrmIOService::readFromFile(const String8& filePath) {
+    LOGV("Entering readFromFile");
+    return ReadWriteUtils::readBytes(filePath);
+}
+
diff --git a/drm/drmioserver/main_drmioserver.cpp b/drm/drmioserver/main_drmioserver.cpp
new file mode 100644
index 0000000..7ed048d
--- /dev/null
+++ b/drm/drmioserver/main_drmioserver.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <private/android_filesystem_config.h>
+
+#include <DrmIOService.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    LOGI("ServiceManager: %p", sm.get());
+    DrmIOService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
+
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
new file mode 100644
index 0000000..5df2ff8
--- /dev/null
+++ b/drm/drmserver/Android.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    main_drmserver.cpp \
+    DrmManager.cpp \
+    DrmManagerService.cpp \
+    StringTokenizer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    libbinder
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/base/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/plugins/common/include
+
+LOCAL_MODULE:= drmserver
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
new file mode 100644
index 0000000..52527dc
--- /dev/null
+++ b/drm/drmserver/DrmManager.cpp
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmManager(Native)"
+#include "utils/Log.h"
+
+#include <utils/String8.h>
+#include <drm/DrmInfo.h>
+#include <drm/DrmInfoEvent.h>
+#include <drm/DrmRights.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+#include <drm/DrmConvertedStatus.h>
+#include <IDrmEngine.h>
+
+#include "DrmManager.h"
+#include "ReadWriteUtils.h"
+
+#define DECRYPT_FILE_ERROR -1
+
+using namespace android;
+
+Vector<int> DrmManager::mUniqueIdVector;
+const String8 DrmManager::EMPTY_STRING("");
+
+DrmManager::DrmManager() :
+    mDecryptSessionId(0),
+    mConvertId(0) {
+
+}
+
+DrmManager::~DrmManager() {
+
+}
+
+int DrmManager::addUniqueId(int uniqueId) {
+    if (0 == uniqueId) {
+        int temp = 0;
+        bool foundUniqueId = false;
+        srand(time(NULL));
+
+        while (!foundUniqueId) {
+            const int size = mUniqueIdVector.size();
+            temp = rand() % 100;
+
+            int index = 0;
+            for (; index < size; ++index) {
+                if (mUniqueIdVector.itemAt(index) == temp) {
+                    foundUniqueId = false;
+                    break;
+                }
+            }
+            if (index == size) {
+                foundUniqueId = true;
+            }
+        }
+        uniqueId = temp;
+    }
+    mUniqueIdVector.push(uniqueId);
+    return uniqueId;
+}
+
+void DrmManager::removeUniqueId(int uniqueId) {
+    for (unsigned int i = 0; i < mUniqueIdVector.size(); i++) {
+        if (uniqueId == mUniqueIdVector.itemAt(i)) {
+            mUniqueIdVector.removeAt(i);
+            break;
+        }
+    }
+}
+
+status_t DrmManager::loadPlugIns(int uniqueId) {
+    String8 pluginDirPath("/system/lib/drm/plugins/native");
+    return loadPlugIns(uniqueId, pluginDirPath);
+}
+
+status_t DrmManager::loadPlugIns(int uniqueId, const String8& plugInDirPath) {
+    if (mSupportInfoToPlugInIdMap.isEmpty()) {
+        mPlugInManager.loadPlugIns(plugInDirPath);
+
+        initializePlugIns(uniqueId);
+
+        populate(uniqueId);
+    } else {
+        initializePlugIns(uniqueId);
+    }
+
+    return DRM_NO_ERROR;
+}
+
+status_t DrmManager::setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
+    Mutex::Autolock _l(mLock);
+    mServiceListeners.add(uniqueId, drmServiceListener);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmManager::unloadPlugIns(int uniqueId) {
+    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
+
+    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
+        rDrmEngine.terminate(uniqueId);
+    }
+
+    if (0 >= mUniqueIdVector.size()) {
+        mConvertSessionMap.clear();
+        mDecryptSessionMap.clear();
+        mSupportInfoToPlugInIdMap.clear();
+        mPlugInManager.unloadPlugIns();
+    }
+    return DRM_NO_ERROR;
+}
+
+DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.getConstraints(uniqueId, path, action);
+    }
+    return NULL;
+}
+
+status_t DrmManager::installDrmEngine(int uniqueId, const String8& absolutePath) {
+    mPlugInManager.loadPlugIn(absolutePath);
+
+    IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(absolutePath);
+    rDrmEngine.initialize(uniqueId);
+    rDrmEngine.setOnInfoListener(uniqueId, this);
+
+    DrmSupportInfo* info = rDrmEngine.getSupportInfo(uniqueId);
+    mSupportInfoToPlugInIdMap.add(*info, absolutePath);
+
+    return DRM_NO_ERROR;
+}
+
+bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+    const String8 plugInId = getSupportedPlugInId(mimeType);
+    bool result = (EMPTY_STRING != plugInId) ? true : false;
+
+    if (NULL != path) {
+        if (result) {
+            IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+            result = rDrmEngine.canHandle(uniqueId, path);
+        } else {
+            result = canHandle(uniqueId, path);
+        }
+    }
+    return result;
+}
+
+DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.processDrmInfo(uniqueId, drmInfo);
+    }
+    return NULL;
+}
+
+bool DrmManager::canHandle(int uniqueId, const String8& path) {
+    bool result = false;
+    Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
+
+    for (unsigned int i = 0; i < plugInPathList.size(); ++i) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInPathList[i]);
+        result = rDrmEngine.canHandle(uniqueId, path);
+
+        if (result) {
+            break;
+        }
+    }
+    return result;
+}
+
+DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
+    }
+    return NULL;
+}
+
+status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
+    }
+    return result;
+}
+
+String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.getOriginalMimeType(uniqueId, path);
+    }
+    return EMPTY_STRING;
+}
+
+int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
+    const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
+    }
+    return DrmObjectType::UNKNOWN;
+}
+
+int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.checkRightsStatus(uniqueId, path, action);
+    }
+    return RightsStatus::RIGHTS_INVALID;
+}
+
+status_t DrmManager::consumeRights(
+    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
+    }
+    return result;
+}
+
+status_t DrmManager::setPlaybackStatus(
+    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+    }
+    return result;
+}
+
+bool DrmManager::validateAction(
+    int uniqueId, const String8& path, int action, const ActionDescription& description) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.validateAction(uniqueId, path, action, description);
+    }
+    return false;
+}
+
+status_t DrmManager::removeRights(int uniqueId, const String8& path) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        result = rDrmEngine.removeRights(uniqueId, path);
+    }
+    return result;
+}
+
+status_t DrmManager::removeAllRights(int uniqueId) {
+    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
+    status_t result = DRM_ERROR_UNKNOWN;
+    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
+        result = rDrmEngine.removeAllRights(uniqueId);
+        if (DRM_NO_ERROR != result) {
+            break;
+        }
+    }
+    return result;
+}
+
+int DrmManager::openConvertSession(int uniqueId, const String8& mimeType) {
+    int convertId = -1;
+
+    const String8 plugInId = getSupportedPlugInId(mimeType);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+
+        if (DRM_NO_ERROR == rDrmEngine.openConvertSession(uniqueId, mConvertId + 1)) {
+            Mutex::Autolock _l(mConvertLock);
+            ++mConvertId;
+            convertId = mConvertId;
+            mConvertSessionMap.add(convertId, &rDrmEngine);
+        }
+    }
+    return convertId;
+}
+
+DrmConvertedStatus* DrmManager::convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) {
+    DrmConvertedStatus *drmConvertedStatus = NULL;
+
+    if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mConvertSessionMap.valueFor(convertId);
+        drmConvertedStatus = drmEngine->convertData(uniqueId, convertId, inputData);
+    }
+    return drmConvertedStatus;
+}
+
+DrmConvertedStatus* DrmManager::closeConvertSession(int uniqueId, int convertId) {
+    DrmConvertedStatus *drmConvertedStatus = NULL;
+
+    if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mConvertSessionMap.valueFor(convertId);
+        drmConvertedStatus = drmEngine->closeConvertSession(uniqueId, convertId);
+        mConvertSessionMap.removeItem(convertId);
+    }
+    return drmConvertedStatus;
+}
+
+status_t DrmManager::getAllSupportInfo(
+                    int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+    Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
+    int size = plugInPathList.size();
+    int validPlugins = 0;
+
+    if (0 < size) {
+        Vector<DrmSupportInfo> drmSupportInfoList;
+
+        for (int i = 0; i < size; ++i) {
+            String8 plugInPath = plugInPathList[i];
+            DrmSupportInfo* drmSupportInfo
+                = mPlugInManager.getPlugIn(plugInPath).getSupportInfo(uniqueId);
+            if (NULL != drmSupportInfo) {
+                drmSupportInfoList.add(*drmSupportInfo);
+                delete drmSupportInfo; drmSupportInfo = NULL;
+            }
+        }
+
+        validPlugins = drmSupportInfoList.size();
+        if (0 < validPlugins) {
+            *drmSupportInfoArray = new DrmSupportInfo[validPlugins];
+            for (int i = 0; i < validPlugins; ++i) {
+                (*drmSupportInfoArray)[i] = drmSupportInfoList[i];
+            }
+        }
+    }
+    *length = validPlugins;
+    return DRM_NO_ERROR;
+}
+
+DecryptHandle* DrmManager::openDecryptSession(int uniqueId, int fd, int offset, int length) {
+    status_t result = DRM_ERROR_CANNOT_HANDLE;
+    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
+
+    DecryptHandle* handle = new DecryptHandle();
+    if (NULL != handle) {
+        Mutex::Autolock _l(mDecryptLock);
+        handle->decryptId = mDecryptSessionId + 1;
+
+        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+            String8 plugInId = plugInIdList.itemAt(index);
+            IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+            result = rDrmEngine.openDecryptSession(uniqueId, handle, fd, offset, length);
+
+            if (DRM_NO_ERROR == result) {
+                ++mDecryptSessionId;
+                mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                break;
+            }
+        }
+    }
+
+    if (DRM_NO_ERROR != result) {
+        delete handle; handle = NULL;
+        LOGE("DrmManager::openDecryptSession: no capable plug-in found");
+    }
+
+    return handle;
+}
+
+status_t DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->closeDecryptSession(uniqueId, decryptHandle);
+        if (DRM_NO_ERROR == result) {
+            mDecryptSessionMap.removeItem(decryptHandle->decryptId);
+        }
+    }
+    return result;
+}
+
+status_t DrmManager::initializeDecryptUnit(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
+    }
+    return result;
+}
+
+status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->decrypt(
+                uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+    }
+    return result;
+}
+
+status_t DrmManager::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    status_t result = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+    }
+    return result;
+}
+
+ssize_t DrmManager::pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset) {
+    ssize_t result = DECRYPT_FILE_ERROR;
+
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        result = drmEngine->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
+    }
+    return result;
+}
+
+void DrmManager::initializePlugIns(int uniqueId) {
+    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
+
+    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
+        rDrmEngine.initialize(uniqueId);
+        rDrmEngine.setOnInfoListener(uniqueId, this);
+    }
+}
+
+void DrmManager::populate(int uniqueId) {
+    Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
+
+    for (unsigned int i = 0; i < plugInPathList.size(); ++i) {
+        String8 plugInPath = plugInPathList[i];
+        DrmSupportInfo* info = mPlugInManager.getPlugIn(plugInPath).getSupportInfo(uniqueId);
+        if (NULL != info) {
+            mSupportInfoToPlugInIdMap.add(*info, plugInPath);
+        }
+    }
+}
+
+String8 DrmManager::getSupportedPlugInId(
+            int uniqueId, const String8& path, const String8& mimeType) {
+    String8 plugInId("");
+
+    if (EMPTY_STRING != mimeType) {
+        plugInId = getSupportedPlugInId(mimeType);
+    } else {
+        plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+    }
+    return plugInId;
+}
+
+String8 DrmManager::getSupportedPlugInId(const String8& mimeType) {
+    String8 plugInId("");
+
+    if (EMPTY_STRING != mimeType) {
+        for (unsigned int index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
+            const DrmSupportInfo& drmSupportInfo = mSupportInfoToPlugInIdMap.keyAt(index);
+
+            if (drmSupportInfo.isSupportedMimeType(mimeType)) {
+                plugInId = mSupportInfoToPlugInIdMap.valueFor(drmSupportInfo);
+                break;
+            }
+        }
+    }
+    return plugInId;
+}
+
+String8 DrmManager::getSupportedPlugInIdFromPath(int uniqueId, const String8& path) {
+    String8 plugInId("");
+    const String8 fileSuffix = path.getPathExtension();
+
+    for (unsigned int index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
+        const DrmSupportInfo& drmSupportInfo = mSupportInfoToPlugInIdMap.keyAt(index);
+
+        if (drmSupportInfo.isSupportedFileSuffix(fileSuffix)) {
+            String8 key = mSupportInfoToPlugInIdMap.valueFor(drmSupportInfo);
+            IDrmEngine& drmEngine = mPlugInManager.getPlugIn(key);
+
+            if (drmEngine.canHandle(uniqueId, path)) {
+                plugInId = key;
+                break;
+            }
+        }
+    }
+    return plugInId;
+}
+
+void DrmManager::onInfo(const DrmInfoEvent& event) {
+    Mutex::Autolock _l(mLock);
+    for (unsigned int index = 0; index < mServiceListeners.size(); index++) {
+        int uniqueId = mServiceListeners.keyAt(index);
+
+        if (uniqueId == event.getUniqueId()) {
+            sp<IDrmServiceListener> serviceListener = mServiceListeners.valueFor(uniqueId);
+            serviceListener->notify(event);
+        }
+    }
+}
+
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
new file mode 100644
index 0000000..843dddb
--- /dev/null
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmManagerService(Native)"
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <utils/threads.h>
+#include <binder/IServiceManager.h>
+#include <sys/stat.h>
+#include "DrmManagerService.h"
+#include "DrmManager.h"
+
+using namespace android;
+
+#define SUCCESS 0
+#define DRM_DIRECTORY_PERMISSION 0700
+#define DRM_PLUGINS_ROOT "/data/drm/plugins"
+#define DRM_PLUGINS_NATIVE "/data/drm/plugins/native"
+#define DRM_PLUGINS_NATIVE_DATABASES "/data/drm/plugins/native/databases"
+
+void DrmManagerService::instantiate() {
+    LOGV("instantiate");
+
+    int res = mkdir(DRM_PLUGINS_ROOT, DRM_DIRECTORY_PERMISSION);
+    if (SUCCESS == res || EEXIST == errno) {
+        res = mkdir(DRM_PLUGINS_NATIVE, DRM_DIRECTORY_PERMISSION);
+        if (SUCCESS == res || EEXIST == errno) {
+            res = mkdir(DRM_PLUGINS_NATIVE_DATABASES, DRM_DIRECTORY_PERMISSION);
+            if (SUCCESS == res || EEXIST == errno) {
+                defaultServiceManager()
+                    ->addService(String16("drm.drmManager"), new DrmManagerService());
+            }
+        }
+    }
+}
+
+DrmManagerService::DrmManagerService() {
+    LOGV("created");
+    mDrmManager = NULL;
+    mDrmManager = new DrmManager();
+}
+
+DrmManagerService::~DrmManagerService() {
+    LOGV("Destroyed");
+    delete mDrmManager; mDrmManager = NULL;
+}
+
+int DrmManagerService::addUniqueId(int uniqueId) {
+    return mDrmManager->addUniqueId(uniqueId);
+}
+
+void DrmManagerService::removeUniqueId(int uniqueId) {
+    mDrmManager->removeUniqueId(uniqueId);
+}
+
+status_t DrmManagerService::loadPlugIns(int uniqueId) {
+    LOGV("Entering load plugins");
+    return mDrmManager->loadPlugIns(uniqueId);
+}
+
+status_t DrmManagerService::loadPlugIns(int uniqueId, const String8& plugInDirPath) {
+    LOGV("Entering load plugins from path");
+    return mDrmManager->loadPlugIns(uniqueId, plugInDirPath);
+}
+
+status_t DrmManagerService::setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
+    LOGV("Entering setDrmServiceListener");
+    mDrmManager->setDrmServiceListener(uniqueId, drmServiceListener);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmManagerService::unloadPlugIns(int uniqueId) {
+    LOGV("Entering unload plugins");
+    return mDrmManager->unloadPlugIns(uniqueId);
+}
+
+status_t DrmManagerService::installDrmEngine(int uniqueId, const String8& drmEngineFile) {
+    LOGV("Entering installDrmEngine");
+    return mDrmManager->installDrmEngine(uniqueId, drmEngineFile);
+}
+
+DrmConstraints* DrmManagerService::getConstraints(
+            int uniqueId, const String8* path, const int action) {
+    LOGV("Entering getConstraints from content");
+    return mDrmManager->getConstraints(uniqueId, path, action);
+}
+
+bool DrmManagerService::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+    LOGV("Entering canHandle");
+    return mDrmManager->canHandle(uniqueId, path, mimeType);
+}
+
+DrmInfoStatus* DrmManagerService::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    LOGV("Entering processDrmInfo");
+    return mDrmManager->processDrmInfo(uniqueId, drmInfo);
+}
+
+DrmInfo* DrmManagerService::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    LOGV("Entering acquireDrmInfo");
+    return mDrmManager->acquireDrmInfo(uniqueId, drmInfoRequest);
+}
+
+status_t DrmManagerService::saveRights(
+            int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    LOGV("Entering saveRights");
+    return mDrmManager->saveRights(uniqueId, drmRights, rightsPath, contentPath);
+}
+
+String8 DrmManagerService::getOriginalMimeType(int uniqueId, const String8& path) {
+    LOGV("Entering getOriginalMimeType");
+    return mDrmManager->getOriginalMimeType(uniqueId, path);
+}
+
+int DrmManagerService::getDrmObjectType(
+           int uniqueId, const String8& path, const String8& mimeType) {
+    LOGV("Entering getDrmObjectType");
+    return mDrmManager->getDrmObjectType(uniqueId, path, mimeType);
+}
+
+int DrmManagerService::checkRightsStatus(
+            int uniqueId, const String8& path, int action) {
+    LOGV("Entering checkRightsStatus");
+    return mDrmManager->checkRightsStatus(uniqueId, path, action);
+}
+
+status_t DrmManagerService::consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    LOGV("Entering consumeRights");
+    return mDrmManager->consumeRights(uniqueId, decryptHandle, action, reserve);
+}
+
+status_t DrmManagerService::setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    LOGV("Entering setPlaybackStatus");
+    return mDrmManager->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+}
+
+bool DrmManagerService::validateAction(
+            int uniqueId, const String8& path,
+            int action, const ActionDescription& description) {
+    LOGV("Entering validateAction");
+    return mDrmManager->validateAction(uniqueId, path, action, description);
+}
+
+status_t DrmManagerService::removeRights(int uniqueId, const String8& path) {
+    LOGV("Entering removeRights");
+    return mDrmManager->removeRights(uniqueId, path);
+}
+
+status_t DrmManagerService::removeAllRights(int uniqueId) {
+    LOGV("Entering removeAllRights");
+    return mDrmManager->removeAllRights(uniqueId);
+}
+
+int DrmManagerService::openConvertSession(int uniqueId, const String8& mimeType) {
+    LOGV("Entering openConvertSession");
+    return mDrmManager->openConvertSession(uniqueId, mimeType);
+}
+
+DrmConvertedStatus* DrmManagerService::convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) {
+    LOGV("Entering convertData");
+    return mDrmManager->convertData(uniqueId, convertId, inputData);
+}
+
+DrmConvertedStatus* DrmManagerService::closeConvertSession(int uniqueId, int convertId) {
+    LOGV("Entering closeConvertSession");
+    return mDrmManager->closeConvertSession(uniqueId, convertId);
+}
+
+status_t DrmManagerService::getAllSupportInfo(
+            int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+    LOGV("Entering getAllSupportInfo");
+    return mDrmManager->getAllSupportInfo(uniqueId, length, drmSupportInfoArray);
+}
+
+DecryptHandle* DrmManagerService::openDecryptSession(
+            int uniqueId, int fd, int offset, int length) {
+    LOGV("Entering DrmManagerService::openDecryptSession");
+    return mDrmManager->openDecryptSession(uniqueId, fd, offset, length);
+}
+
+status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    LOGV("Entering closeDecryptSession");
+    return mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
+}
+
+status_t DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    LOGV("Entering initializeDecryptUnit");
+    return mDrmManager->initializeDecryptUnit(uniqueId,decryptHandle, decryptUnitId, headerInfo);
+}
+
+status_t DrmManagerService::decrypt(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    LOGV("Entering decrypt");
+    return mDrmManager->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+}
+
+status_t DrmManagerService::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    LOGV("Entering finalizeDecryptUnit");
+    return mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+}
+
+ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset) {
+    LOGV("Entering pread");
+    return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
+}
+
diff --git a/drm/drmserver/StringTokenizer.cpp b/drm/drmserver/StringTokenizer.cpp
new file mode 100644
index 0000000..2130a00
--- /dev/null
+++ b/drm/drmserver/StringTokenizer.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StringTokenizer.h"
+
+using namespace android;
+
+StringTokenizer::StringTokenizer(const String8& string, const String8& delimiter) {
+    splitString(string, delimiter);
+}
+
+void StringTokenizer::splitString(const String8& string, const String8& delimiter) {
+    for (unsigned int i = 0; i < string.length(); i++) {
+        unsigned int position = string.find(delimiter.string(), i);
+        if (string.length() != position) {
+            String8 token(string.string()+i, position-i);
+            if (token.length()) {
+                mStringTokenizerVector.push(token);
+                i = position + delimiter.length() - 1;
+            }
+        } else {
+            mStringTokenizerVector.push(String8(string.string()+i, string.length()-i));
+            break;
+        }
+    }
+}
+
+StringTokenizer::Iterator StringTokenizer::iterator() {
+    return Iterator(this);
+}
+
+StringTokenizer::Iterator::Iterator(const StringTokenizer::Iterator& iterator) :
+    mStringTokenizer(iterator.mStringTokenizer),
+    mIndex(iterator.mIndex) {
+}
+
+StringTokenizer::Iterator& StringTokenizer::Iterator::operator=(
+            const StringTokenizer::Iterator& iterator) {
+    mStringTokenizer = iterator.mStringTokenizer;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool StringTokenizer::Iterator::hasNext() {
+    return mIndex < mStringTokenizer->mStringTokenizerVector.size();
+}
+
+String8& StringTokenizer::Iterator::next() {
+    String8& value = mStringTokenizer->mStringTokenizerVector.editItemAt(mIndex);
+    mIndex++;
+    return value;
+}
+
diff --git a/drm/drmserver/main_drmserver.cpp b/drm/drmserver/main_drmserver.cpp
new file mode 100644
index 0000000..6d10646
--- /dev/null
+++ b/drm/drmserver/main_drmserver.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <private/android_filesystem_config.h>
+
+#include <DrmManagerService.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    LOGI("ServiceManager: %p", sm.get());
+    DrmManagerService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
+
diff --git a/drm/java/android/drm/DrmConvertedStatus.java b/drm/java/android/drm/DrmConvertedStatus.java
new file mode 100644
index 0000000..f200552
--- /dev/null
+++ b/drm/java/android/drm/DrmConvertedStatus.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This is an entity class which wraps the status of the conversion, the converted
+ * data/checksum data and the offset. Offset is going to be used in the case of close
+ * session where the agent will inform where the header and body signature should be added
+ *
+ * As a result of {@link DrmManagerClient#convertData(int, byte [])} and
+ * {@link DrmManagerClient#closeConvertSession(int)} an instance of DrmConvertedStatus
+ * would be returned.
+ *
+ */
+public class DrmConvertedStatus {
+    // Should be in sync with DrmConvertedStatus.cpp
+    public static final int STATUS_OK = 1;
+    public static final int STATUS_INPUTDATA_ERROR = 2;
+    public static final int STATUS_ERROR = 3;
+
+    public final int statusCode;
+    public final byte[] convertedData;
+    public final int offset;
+
+    /**
+     * constructor to create DrmConvertedStatus object with given parameters
+     *
+     * @param _statusCode Status of the conversion
+     * @param _convertedData Converted data/checksum data
+     * @param _offset Offset value
+     */
+    public DrmConvertedStatus(int _statusCode, byte[] _convertedData, int _offset) {
+        statusCode = _statusCode;
+        convertedData = _convertedData;
+        offset = _offset;
+    }
+}
+
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
new file mode 100644
index 0000000..8e71634
--- /dev/null
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This is an entity class which would be passed to caller in
+ * {@link DrmManagerClient.OnErrorListener#onError(DrmManagerClient, DrmErrorEvent)}
+ *
+ */
+public class DrmErrorEvent extends DrmEvent {
+    /**
+     * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights.
+     */
+    public static final int TYPE_RIGHTS_NOT_INSTALLED = 2001;
+    /**
+     * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights.
+     */
+    public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002;
+    /**
+     * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent.
+     */
+    public static final int TYPE_NOT_SUPPORTED = 2003;
+    /**
+     * TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
+     * Can in the future perhaps be used to trigger garbage collector.
+     */
+    public static final int TYPE_OUT_OF_MEMORY = 2004;
+    /**
+     * TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
+     * can be made to renew rights.
+     */
+    public static final int TYPE_NO_INTERNET_CONNECTION = 2005;
+    /**
+     * TYPE_REGISTRATION_FAILED, when failed to register with the service.
+     */
+    public static final int TYPE_REGISTRATION_FAILED = 2006;
+    /**
+     * TYPE_UNREGISTRATION_FAILED, when failed to unregister with the service.
+     */
+    public static final int TYPE_UNREGISTRATION_FAILED = 2007;
+    /**
+     * TYPE_RIGHTS_ACQUISITION_FAILED, when failed to acquire the rights information required.
+     */
+    public static final int TYPE_RIGHTS_ACQUISITION_FAILED = 2008;
+    /**
+     * TYPE_INITIALIZE_FAILED, when failed to load and initialize the available plugins.
+     */
+    public static final int TYPE_INITIALIZE_FAILED = 2009;
+    /**
+     * TYPE_FINALIZE_FAILED, when failed to unload and finalize the loaded plugins.
+     */
+    public static final int TYPE_FINALIZE_FAILED = 2010;
+    /**
+     * TYPE_REMOVE_ALL_RIGHTS_FAILED, when failed to remove all the rights objects
+     * associated with all DRM schemes.
+     */
+    public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2011;
+    /**
+     * TYPE_DRM_INFO_ACQUISITION_FAILED, when failed to get the required information to
+     * communicate with the service.
+     */
+    public static final int TYPE_DRM_INFO_ACQUISITION_FAILED = 2012;
+
+    /**
+     * constructor to create DrmErrorEvent object with given parameters
+     *
+     * @param uniqueId Unique session identifier
+     * @param type Type of information
+     * @param message Message description
+     */
+    public DrmErrorEvent(int uniqueId, int type, String message) {
+        super(uniqueId, type, message);
+    }
+}
+
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
new file mode 100644
index 0000000..d6e0c3a
--- /dev/null
+++ b/drm/java/android/drm/DrmEvent.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This is the base class which would be used to notify the caller
+ * about any event occurred in DRM framework.
+ *
+ */
+public class DrmEvent {
+    /**
+     * Constant field signifies that unload and finalize the loaded plugins successfully
+     */
+    public static final int TYPE_FINALIZED = 1001;
+    /**
+     * Constant field signifies that register with the service successfully
+     */
+    public static final int TYPE_REGISTERED = 1002;
+    /**
+     * Constant field signifies that load and initialized the available plugins successfully
+     */
+    public static final int TYPE_INITIALIZED = 1003;
+    /**
+     * Constant field signifies that unregister with the service successfully
+     */
+    public static final int TYPE_UNREGISTERED = 1004;
+    /**
+     * Constant field signifies that rights information is acquired successfully
+     */
+    public static final int TYPE_RIGHTS_ACQUIRED = 1005;
+    /**
+     * Constant field signifies that all the rights information associated with
+     * all DRM schemes are removed successfully
+     */
+    public static final int TYPE_ALL_RIGHTS_REMOVED = 1006;
+    /**
+     * Constant field signifies that the required information to communicate with
+     * the service is acquired sucessfully
+     */
+    public static final int TYPE_DRM_INFO_ACQUIRED = 1007;
+
+    public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+    public static final String DRM_INFO_OBJECT = "drm_info_object";
+
+    private final int mUniqueId;
+    private final int mType;
+    private String mMessage = "";
+
+    /**
+     * constructor for DrmEvent class
+     *
+     * @param uniqueId Unique session identifier
+     * @param type Type of information
+     * @param message Message description
+     */
+    protected DrmEvent(int uniqueId, int type, String message) {
+        mUniqueId = uniqueId;
+        mType = type;
+
+        if (null != message) {
+            mMessage = message;
+        }
+    }
+
+    /**
+     * Returns the Unique Id associated with this object
+     *
+     * @return Unique Id
+     */
+    public int getUniqueId() {
+        return mUniqueId;
+    }
+
+    /**
+     * Returns the Type of information associated with this object
+     *
+     * @return Type of information
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the message description associated with this object
+     *
+     * @return message description
+     */
+    public String getMessage() {
+        return mMessage;
+    }
+}
+
diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java
new file mode 100644
index 0000000..7d3fbf1
--- /dev/null
+++ b/drm/java/android/drm/DrmInfo.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * This is an entity class in which necessary information required to transact
+ * between device and online DRM server is described. DRM Framework achieves
+ * server registration, license acquisition and any other server related transaction
+ * by passing an instance of this class to {@link DrmManagerClient#processDrmInfo(DrmInfo)}.
+ *
+ * Caller can retrieve the {@link DrmInfo} instance by using
+ * {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)}
+ * by passing {@link DrmInfoRequest} instance.
+ *
+ */
+public class DrmInfo {
+    private byte[] mData;
+    private final String mMimeType;
+    private final int mInfoType;
+    // It would be used to add attributes specific to
+    // DRM scheme such as account id, path or multiple path's
+    private final HashMap<String, Object> mAttributes = new HashMap<String, Object>();
+
+    /**
+     * constructor to create DrmInfo object with given parameters
+     *
+     * @param infoType Type of information
+     * @param data Trigger data
+     * @param mimeType MIME type
+     */
+    public DrmInfo(int infoType, byte[] data, String mimeType) {
+        mInfoType = infoType;
+        mMimeType = mimeType;
+        mData = data;
+    }
+
+    /**
+     * constructor to create DrmInfo object with given parameters
+     *
+     * @param infoType Type of information
+     * @param path Trigger data
+     * @param mimeType MIME type
+     */
+    public DrmInfo(int infoType, String path, String mimeType) {
+        mInfoType = infoType;
+        mMimeType = mimeType;
+        try {
+            mData = DrmUtils.readBytes(path);
+        } catch (IOException e) {
+            // As the given path is invalid,
+            // set mData = null, so that further processDrmInfo()
+            // call would fail with IllegalArgumentException because of mData = null
+            mData = null;
+        }
+    }
+
+    /**
+     * Adds optional information as <key, value> pair to this object
+     *
+     * @param key Key to add
+     * @param value Value to add
+     *     To put custom object into DrmInfo, custom object has to
+     *     override toString() implementation.
+     */
+    public void put(String key, Object value) {
+        mAttributes.put(key, value);
+    }
+
+    /**
+     * Retrieves the value of given key, if not found returns null
+     *
+     * @param key Key whose value to be retrieved
+     * @return The value or null
+     */
+    public Object get(String key) {
+        return mAttributes.get(key);
+    }
+
+    /**
+     * Returns Iterator object to walk through the keys associated with this instance
+     *
+     * @return Iterator object
+     */
+    public Iterator<String> keyIterator() {
+        return mAttributes.keySet().iterator();
+    }
+
+    /**
+     * Returns Iterator object to walk through the values associated with this instance
+     *
+     * @return Iterator object
+     */
+    public Iterator<Object> iterator() {
+        return mAttributes.values().iterator();
+    }
+
+    /**
+     * Returns the trigger data associated with this object
+     *
+     * @return Trigger data
+     */
+    public byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Returns the mimetype associated with this object
+     *
+     * @return MIME type
+     */
+    public String getMimeType() {
+        return mMimeType;
+    }
+
+    /**
+     * Returns information type associated with this instance
+     *
+     * @return Information type
+     */
+    public int getInfoType() {
+        return mInfoType;
+    }
+
+    /**
+     * Returns whether this instance is valid or not
+     *
+     * @return
+     *     true if valid
+     *     false if invalid
+     */
+     boolean isValid() {
+        return (null != mMimeType && !mMimeType.equals("")
+                && null != mData && mData.length > 0 && DrmInfoRequest.isValidType(mInfoType));
+    }
+}
+
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
new file mode 100644
index 0000000..a778e06
--- /dev/null
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This is an entity class which would be passed to caller in
+ * {@link DrmManagerClient.OnInfoListener#onInfo(DrmManagerClient, DrmInfoEvent)}
+ *
+ */
+public class DrmInfoEvent extends DrmEvent {
+    /**
+     * TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been already done
+     * by another account ID.
+     */
+    public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1;
+    /**
+     * TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
+     */
+    public static final int TYPE_REMOVE_RIGHTS = 2;
+    /**
+     * TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
+     */
+    public static final int TYPE_RIGHTS_INSTALLED = 3;
+    /**
+     * TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone,
+     * wait before calling checkRights again.
+     */
+    public static final int TYPE_WAIT_FOR_RIGHTS = 4;
+    /**
+     * TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
+     * already done for the given account.
+     */
+    public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+
+    /**
+     * constructor to create DrmInfoEvent object with given parameters
+     *
+     * @param uniqueId Unique session identifier
+     * @param type Type of information
+     * @param message Message description
+     */
+    public DrmInfoEvent(int uniqueId, int type, String message) {
+        super(uniqueId, type, message);
+    }
+}
+
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
new file mode 100644
index 0000000..a5a799c
--- /dev/null
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * This is an entity class used to pass required parameters to get
+ * the necessary information to communicate with online DRM server
+ *
+ * An instance of this class is passed to {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)}
+ * to get the instance of {@link DrmInfo}
+ *
+ */
+public class DrmInfoRequest {
+    // Changes in following constants should be in sync with DrmInfoRequest.cpp
+    /**
+     * Constants defines the type of {@link DrmInfoRequest}
+     */
+    public static final int TYPE_REGISTRATION_INFO = 1;
+    public static final int TYPE_UNREGISTRATION_INFO = 2;
+    public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3;
+    public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4;
+
+    /**
+     * Key to pass the unique id for the account or the user
+     */
+    public static final String ACCOUNT_ID = "account_id";
+
+    /**
+     * Key to pass the unique id used for subscription
+     */
+    public static final String SUBSCRIPTION_ID = "subscription_id";
+
+    private final int mInfoType;
+    private final String mMimeType;
+    private final HashMap<String, Object> mRequestInformation = new HashMap<String, Object>();
+
+    /**
+     * constructor to create DrmInfoRequest object with type and mimetype
+     *
+     * @param infoType Type of information
+     * @param mimeType MIME type
+     */
+    public DrmInfoRequest(int infoType, String mimeType) {
+        mInfoType = infoType;
+        mMimeType = mimeType;
+    }
+
+    /**
+     * Returns the mimetype associated with this object
+     *
+     * @return MIME type
+     */
+    public String getMimeType() {
+        return mMimeType;
+    }
+
+    /**
+     * Returns Information type associated with this instance
+     *
+     * @return Information type
+     */
+    public int getInfoType() {
+        return mInfoType;
+    }
+
+    /**
+     * Adds optional information as <key, value> pair to this object.
+     *
+     * @param key Key to add
+     * @param value Value to add
+     */
+    public void put(String key, Object value) {
+        mRequestInformation.put(key, value);
+    }
+
+    /**
+     * Retrieves the value of given key, if not found returns null
+     *
+     * @param key Key whose value to be retrieved
+     * @return The value or null
+     */
+    public Object get(String key) {
+        return mRequestInformation.get(key);
+    }
+
+    /**
+     * Returns Iterator object to walk through the keys associated with this instance
+     *
+     * @return Iterator object
+     */
+    public Iterator<String> keyIterator() {
+        return mRequestInformation.keySet().iterator();
+    }
+
+    /**
+     * Returns Iterator object to walk through the values associated with this instance
+     *
+     * @return Iterator object
+     */
+    public Iterator<Object> iterator() {
+        return mRequestInformation.values().iterator();
+    }
+
+    /**
+     * Returns whether this instance is valid or not
+     *
+     * @return
+     *     true if valid
+     *     false if invalid
+     */
+    boolean isValid() {
+        return (null != mMimeType && !mMimeType.equals("")
+                && null != mRequestInformation && isValidType(mInfoType));
+    }
+
+    /* package */ static boolean isValidType(int infoType) {
+        boolean isValid = false;
+
+        switch (infoType) {
+        case TYPE_REGISTRATION_INFO:
+        case TYPE_UNREGISTRATION_INFO:
+        case TYPE_RIGHTS_ACQUISITION_INFO:
+        case TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO:
+            isValid = true;
+            break;
+        }
+        return isValid;
+    }
+}
+
diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java
new file mode 100644
index 0000000..7e9ca3e
--- /dev/null
+++ b/drm/java/android/drm/DrmInfoStatus.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This is an entity class which wraps the result of communication between device
+ * and online DRM server.
+ *
+ * As a result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} an instance of DrmInfoStatus
+ * would be returned. This class holds {@link ProcessedData}, which could be used to instantiate
+ * {@link DrmRights#DrmRights(ProcessedData, String)} in license acquisition.
+ *
+ */
+public class DrmInfoStatus {
+    // Should be in sync with DrmInfoStatus.cpp
+    public static final int STATUS_OK = 1;
+    public static final int STATUS_ERROR = 2;
+
+    public final int statusCode;
+    public final String mimeType;
+    public final ProcessedData data;
+
+    /**
+     * constructor to create DrmInfoStatus object with given parameters
+     *
+     * @param _statusCode Status of the communication
+     * @param _data The processed data
+     * @param _mimeType MIME type
+     */
+    public DrmInfoStatus(int _statusCode, ProcessedData _data, String _mimeType) {
+        statusCode = _statusCode;
+        data = _data;
+        mimeType = _mimeType;
+    }
+}
+
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
new file mode 100644
index 0000000..147c530
--- /dev/null
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Interface of DRM Framework.
+ * Java application will instantiate this class
+ * to access DRM agent through DRM Framework.
+ *
+ */
+public class DrmManagerClient {
+    /**
+     * Constant field signifies the success or no error occurred
+     */
+    public static final int ERROR_NONE = 0;
+    /**
+     * Constant field signifies that error occurred and the reason is not known
+     */
+    public static final int ERROR_UNKNOWN = -2000;
+
+    private static final String TAG = "DrmManagerClient";
+
+    static {
+        // Load the respective library
+        System.loadLibrary("drmframework_jni");
+    }
+
+    /**
+     * Interface definition of a callback to be invoked to communicate
+     * some info and/or warning about DrmManagerClient.
+     */
+    public interface OnInfoListener {
+        /**
+         * Called to indicate an info or a warning.
+         *
+         * @param client DrmManagerClient instance
+         * @param event instance which wraps reason and necessary information
+         */
+        public void onInfo(DrmManagerClient client, DrmInfoEvent event);
+    }
+
+    /**
+     * Interface definition of a callback to be invoked to communicate
+     * the result of time consuming APIs asynchronously
+     */
+    public interface OnEventListener {
+        /**
+         * Called to indicate the result of asynchronous APIs.
+         *
+         * @param client DrmManagerClient instance
+         * @param event instance which wraps type and message
+         * @param attributes resultant values in key and value pair.
+         */
+        public void onEvent(DrmManagerClient client, DrmEvent event,
+                HashMap<String, Object> attributes);
+    }
+
+    /**
+     * Interface definition of a callback to be invoked to communicate
+     * the error occurred
+     */
+    public interface OnErrorListener {
+        /**
+         * Called to indicate the error occurred.
+         *
+         * @param client DrmManagerClient instance
+         * @param event instance which wraps error type and message
+         */
+        public void onError(DrmManagerClient client, DrmErrorEvent event);
+    }
+
+    private static final int STATE_UNINITIALIZED = 0;
+    private static final int STATE_INITIALIZED = 1;
+
+    private static final int ACTION_INITIALIZE = 1000;
+    private static final int ACTION_FINALIZE = 1001;
+    private static final int ACTION_REMOVE_ALL_RIGHTS = 1002;
+    private static final int ACTION_ACQUIRE_DRM_INFO = 1003;
+    private static final int ACTION_PROCESS_DRM_INFO = 1004;
+
+    private int mUniqueId;
+    private int mNativeContext;
+    private Context mContext;
+    private InfoHandler mInfoHandler;
+    private EventHandler mEventHandler;
+    private OnInfoListener mOnInfoListener;
+    private OnEventListener mOnEventListener;
+    private OnErrorListener mOnErrorListener;
+    private int mCurrentState = STATE_UNINITIALIZED;
+
+    private class EventHandler extends Handler {
+
+        public EventHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void handleMessage(Message msg) {
+            DrmEvent event = null;
+            DrmErrorEvent error = null;
+            HashMap<String, Object> attributes = new HashMap<String, Object>();
+
+            switch(msg.what) {
+            case ACTION_INITIALIZE: {
+                if (ERROR_NONE == _loadPlugIns(mUniqueId, msg.obj)) {
+                    mCurrentState = STATE_INITIALIZED;
+                    event = new DrmEvent(mUniqueId, DrmEvent.TYPE_INITIALIZED, null);
+                } else {
+                    error = new DrmErrorEvent(mUniqueId,
+                            DrmErrorEvent.TYPE_INITIALIZE_FAILED, null);
+                }
+                break;
+            }
+            case ACTION_ACQUIRE_DRM_INFO: {
+                final DrmInfoRequest request = (DrmInfoRequest) msg.obj;
+                DrmInfo drmInfo = _acquireDrmInfo(mUniqueId, request);
+                if (null != drmInfo) {
+                    attributes.put(DrmEvent.DRM_INFO_OBJECT, drmInfo);
+                    event = new DrmEvent(mUniqueId, DrmEvent.TYPE_DRM_INFO_ACQUIRED, null);
+                } else {
+                    error = new DrmErrorEvent(mUniqueId,
+                            DrmErrorEvent.TYPE_DRM_INFO_ACQUISITION_FAILED, null);
+                }
+                break;
+            }
+            case ACTION_PROCESS_DRM_INFO: {
+                final DrmInfo drmInfo = (DrmInfo) msg.obj;
+                DrmInfoStatus status = _processDrmInfo(mUniqueId, drmInfo);
+                if (null != status && DrmInfoStatus.STATUS_OK == status.statusCode) {
+                    attributes.put(DrmEvent.DRM_INFO_STATUS_OBJECT, status);
+                    event = new DrmEvent(mUniqueId, getEventType(drmInfo.getInfoType()), null);
+                } else {
+                    error = new DrmErrorEvent(mUniqueId,
+                            getErrorType(drmInfo.getInfoType()), null);
+                }
+                break;
+            }
+            case ACTION_REMOVE_ALL_RIGHTS: {
+                if (ERROR_NONE == _removeAllRights(mUniqueId)) {
+                    event = new DrmEvent(mUniqueId, DrmEvent.TYPE_ALL_RIGHTS_REMOVED, null);
+                } else {
+                    error = new DrmErrorEvent(mUniqueId,
+                            DrmErrorEvent.TYPE_REMOVE_ALL_RIGHTS_FAILED, null);
+                }
+                break;
+            }
+            case ACTION_FINALIZE: {
+                if (ERROR_NONE == _unloadPlugIns(mUniqueId)) {
+                    mCurrentState = STATE_UNINITIALIZED;
+                    event = new DrmEvent(mUniqueId, DrmEvent.TYPE_FINALIZED, null);
+                } else {
+                    error = new DrmErrorEvent(mUniqueId,
+                            DrmErrorEvent.TYPE_FINALIZE_FAILED, null);
+                }
+                break;
+            }
+            default:
+                Log.e(TAG, "Unknown message type " + msg.what);
+                return;
+            }
+            if (null != mOnEventListener && null != event) {
+                mOnEventListener.onEvent(DrmManagerClient.this, event, attributes);
+            }
+            if (null != mOnErrorListener && null != error) {
+                mOnErrorListener.onError(DrmManagerClient.this, error);
+            }
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public static void notify(
+            Object thisReference, int uniqueId, int infoType, String message) {
+        DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
+
+        if (null != instance && null != instance.mInfoHandler) {
+            Message m = instance.mInfoHandler.obtainMessage(
+                InfoHandler.INFO_EVENT_TYPE, uniqueId, infoType, message);
+            instance.mInfoHandler.sendMessage(m);
+        }
+    }
+
+    private class InfoHandler extends Handler {
+        public static final int INFO_EVENT_TYPE = 1;
+
+        public InfoHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void handleMessage(Message msg) {
+            DrmInfoEvent event = null;
+            DrmErrorEvent error = null;
+
+            switch (msg.what) {
+            case InfoHandler.INFO_EVENT_TYPE:
+                int uniqueId = msg.arg1;
+                int infoType = msg.arg2;
+                String message = msg.obj.toString();
+
+                switch (infoType) {
+                case DrmInfoEvent.TYPE_REMOVE_RIGHTS: {
+                    try {
+                        DrmUtils.removeFile(message);
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                    event = new DrmInfoEvent(uniqueId, infoType, message);
+                    break;
+                }
+                case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT: {
+                    event = new DrmInfoEvent(uniqueId, infoType, message);
+                    break;
+                }
+                default:
+                    error = new DrmErrorEvent(uniqueId, infoType, message);
+                    break;
+                }
+
+                if (null != mOnInfoListener && null != event) {
+                    mOnInfoListener.onInfo(DrmManagerClient.this, event);
+                }
+                if (null != mOnErrorListener && null != error) {
+                    mOnErrorListener.onError(DrmManagerClient.this, error);
+                }
+                return;
+            default:
+                Log.e(TAG, "Unknown message type " + msg.what);
+                return;
+            }
+        }
+    }
+
+    /**
+     * To instantiate DrmManagerClient
+     *
+     * @param context context of the caller
+     */
+    public DrmManagerClient(Context context) {
+        mContext = context;
+        Looper looper;
+
+        if (null != (looper = Looper.myLooper())) {
+            mInfoHandler = new InfoHandler(looper);
+        } else if (null != (looper = Looper.getMainLooper())) {
+            mInfoHandler = new InfoHandler(looper);
+        } else {
+            mInfoHandler = null;
+        }
+
+        HandlerThread thread = new HandlerThread("DrmManagerClient.EventHandler");
+        thread.start();
+        mEventHandler = new EventHandler(thread.getLooper());
+
+        // save the unique id
+        mUniqueId = hashCode();
+    }
+
+    /**
+     * Register a callback to be invoked when the caller required to receive
+     * supplementary information.
+     *
+     * @param infoListener
+     */
+    public synchronized void setOnInfoListener(OnInfoListener infoListener) {
+        if (null != infoListener) {
+            mOnInfoListener = infoListener;
+        }
+    }
+
+    /**
+     * Register a callback to be invoked when the caller required to receive
+     * the result of asynchronous APIs.
+     *
+     * @param eventListener
+     */
+    public synchronized void setOnEventListener(OnEventListener eventListener) {
+        if (null != eventListener) {
+            mOnEventListener = eventListener;
+        }
+    }
+
+    /**
+     * Register a callback to be invoked when the caller required to receive
+     * error result of asynchronous APIs.
+     *
+     * @param errorListener
+     */
+    public synchronized void setOnErrorListener(OnErrorListener errorListener) {
+        if (null != errorListener) {
+            mOnErrorListener = errorListener;
+        }
+    }
+
+    /**
+     * Initializes DrmFramework, which loads all available plug-ins
+     * in the default plug-in directory path
+     *
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int loadPlugIns() {
+        int result = ERROR_UNKNOWN;
+        if (STATE_UNINITIALIZED == getState()) {
+            if (null != mEventHandler) {
+                Message msg = mEventHandler.obtainMessage(
+                        ACTION_INITIALIZE, new WeakReference<DrmManagerClient>(this));
+                result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+            }
+        } else {
+            result = ERROR_NONE;
+        }
+        return result;
+    }
+
+    /**
+     * Finalize DrmFramework, which release resources associated with each plug-in
+     * and unload all plug-ins.
+     *
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int unloadPlugIns() {
+        int result = ERROR_UNKNOWN;
+        if (STATE_INITIALIZED == getState()) {
+            if (null != mEventHandler) {
+                Message msg = mEventHandler.obtainMessage(ACTION_FINALIZE);
+                result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+            }
+        } else {
+            result = ERROR_NONE;
+        }
+        return result;
+    }
+
+    /**
+     * Retrieves informations about all the plug-ins registered with DrmFramework.
+     *
+     * @return Array of DrmEngine plug-in strings
+     */
+    public String[] getAvailableDrmEngines() {
+        if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+
+        DrmSupportInfo[] supportInfos = _getAllSupportInfo(mUniqueId);
+        ArrayList<String> descriptions = new ArrayList<String>();
+
+        for (int i = 0; i < supportInfos.length; i++) {
+            descriptions.add(supportInfos[i].getDescriprition());
+        }
+
+        String[] drmEngines = new String[descriptions.size()];
+        return descriptions.toArray(drmEngines);
+    }
+
+    /**
+     * Get constraints information evaluated from DRM content
+     *
+     * @param path Content path from where DRM constraints would be retrieved.
+     * @param action Actions defined in {@link DrmStore.Action}
+     * @return ContentValues instance in which constraints key-value pairs are embedded
+     *         or null in case of failure
+     */
+    public ContentValues getConstraints(String path, int action) {
+        if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
+            throw new IllegalArgumentException("Given usage or path is invalid/null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _getConstraints(mUniqueId, path, action);
+    }
+
+    /**
+     * Get constraints information evaluated from DRM content
+     *
+     * @param uri The Content URI of the data
+     * @param action Actions defined in {@link DrmStore.Action}
+     * @return ContentValues instance in which constraints key-value pairs are embedded
+     *         or null in case of failure
+     */
+    public ContentValues getConstraints(Uri uri, int action) {
+        return getConstraints(convertUriToPath(uri), action);
+    }
+
+    /**
+     * Save DRM rights to specified rights path
+     * and make association with content path.
+     *
+     * <p class="note">In case of OMA or WM-DRM, rightsPath and contentPath could be null.</p>
+     *
+     * @param drmRights DrmRights to be saved
+     * @param rightsPath File path where rights to be saved
+     * @param contentPath File path where content was saved
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     * @throws IOException if failed to save rights information in the given path
+     */
+    public int saveRights(
+            DrmRights drmRights, String rightsPath, String contentPath) throws IOException {
+        if (null == drmRights || !drmRights.isValid()) {
+            throw new IllegalArgumentException("Given drmRights or contentPath is not valid");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        if (null != rightsPath && !rightsPath.equals("")) {
+            DrmUtils.writeToFile(rightsPath, drmRights.getData());
+        }
+        return _saveRights(mUniqueId, drmRights, rightsPath, contentPath);
+    }
+
+    /**
+     * Install new DRM Engine Plug-in at the runtime
+     *
+     * @param engineFilePath Path of the plug-in file to be installed
+     * {@hide}
+     */
+    public void installDrmEngine(String engineFilePath) {
+        if (null == engineFilePath || engineFilePath.equals("")) {
+            throw new IllegalArgumentException(
+                "Given engineFilePath: "+ engineFilePath + "is not valid");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        _installDrmEngine(mUniqueId, engineFilePath);
+    }
+
+    /**
+     * Check whether the given mimetype or path can be handled.
+     *
+     * @param path Path of the content to be handled
+     * @param mimeType Mimetype of the object to be handled
+     * @return
+     *        true - if the given mimeType or path can be handled
+     *        false - cannot be handled. false will be return in case
+     *        the state is uninitialized
+     */
+    public boolean canHandle(String path, String mimeType) {
+        if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
+            throw new IllegalArgumentException("Path or the mimetype should be non null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _canHandle(mUniqueId, path, mimeType);
+    }
+
+    /**
+     * Check whether the given mimetype or uri can be handled.
+     *
+     * @param uri The content URI of the data
+     * @param mimeType Mimetype of the object to be handled
+     * @return
+     *        true - if the given mimeType or path can be handled
+     *        false - cannot be handled. false will be return in case
+     *        the state is uninitialized
+     */
+    public boolean canHandle(Uri uri, String mimeType) {
+        if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
+            throw new IllegalArgumentException("Uri or the mimetype should be non null");
+        }
+        return canHandle(convertUriToPath(uri), mimeType);
+    }
+
+    /**
+     * Executes given drm information based on its type
+     *
+     * @param drmInfo Information needs to be processed
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int processDrmInfo(DrmInfo drmInfo) {
+        if (null == drmInfo || !drmInfo.isValid()) {
+            throw new IllegalArgumentException("Given drmInfo is invalid/null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        int result = ERROR_UNKNOWN;
+        if (null != mEventHandler) {
+            Message msg = mEventHandler.obtainMessage(ACTION_PROCESS_DRM_INFO, drmInfo);
+            result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+        }
+        return result;
+    }
+
+    /**
+     * Retrieves necessary information for register, unregister or rights acquisition.
+     *
+     * @param drmInfoRequest Request information to retrieve drmInfo
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
+        if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
+            throw new IllegalArgumentException("Given drmInfoRequest is invalid/null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        int result = ERROR_UNKNOWN;
+        if (null != mEventHandler) {
+            Message msg = mEventHandler.obtainMessage(ACTION_ACQUIRE_DRM_INFO, drmInfoRequest);
+            result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+        }
+        return result;
+    }
+
+    /**
+     * Retrieves the type of the protected object (content, rights, etc..)
+     * using specified path or mimetype. At least one parameter should be non null
+     * to retrieve DRM object type
+     *
+     * @param path Path of the content or null.
+     * @param mimeType Mimetype of the content or null.
+     * @return Type of the DRM content.
+     * @see DrmStore.DrmObjectType
+     */
+    public int getDrmObjectType(String path, String mimeType) {
+        if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
+            throw new IllegalArgumentException("Path or the mimetype should be non null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _getDrmObjectType(mUniqueId, path, mimeType);
+    }
+
+    /**
+     * Retrieves the type of the protected object (content, rights, etc..)
+     * using specified uri or mimetype. At least one parameter should be non null
+     * to retrieve DRM object type
+     *
+     * @param uri The content URI of the data
+     * @param mimeType Mimetype of the content or null.
+     * @return Type of the DRM content.
+     * @see DrmStore.DrmObjectType
+     */
+    public int getDrmObjectType(Uri uri, String mimeType) {
+        if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
+            throw new IllegalArgumentException("Uri or the mimetype should be non null");
+        }
+        String path = "";
+        try {
+            path = convertUriToPath(uri);
+        } catch (Exception e) {
+            // Even uri is invalid the mimetype shall be valid, so allow to proceed further.
+            Log.w(TAG, "Given Uri could not be found in media store");
+        }
+        return getDrmObjectType(path, mimeType);
+    }
+
+    /**
+     * Retrieves the mime type embedded inside the original content
+     *
+     * @param path Path of the protected content
+     * @return Mimetype of the original content, such as "video/mpeg"
+     */
+    public String getOriginalMimeType(String path) {
+        if (null == path || path.equals("")) {
+            throw new IllegalArgumentException("Given path should be non null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _getOriginalMimeType(mUniqueId, path);
+    }
+
+    /**
+     * Retrieves the mime type embedded inside the original content
+     *
+     * @param uri The content URI of the data
+     * @return Mimetype of the original content, such as "video/mpeg"
+     */
+    public String getOriginalMimeType(Uri uri) {
+        if (null == uri || Uri.EMPTY == uri) {
+            throw new IllegalArgumentException("Given uri is not valid");
+        }
+        return getOriginalMimeType(convertUriToPath(uri));
+    }
+
+    /**
+     * Check whether the given content has valid rights or not
+     *
+     * @param path Path of the protected content
+     * @return Status of the rights for the protected content
+     * @see DrmStore.RightsStatus
+     */
+    public int checkRightsStatus(String path) {
+        return checkRightsStatus(path, DrmStore.Action.DEFAULT);
+    }
+
+    /**
+     * Check whether the given content has valid rights or not
+     *
+     * @param uri The content URI of the data
+     * @return Status of the rights for the protected content
+     * @see DrmStore.RightsStatus
+     */
+    public int checkRightsStatus(Uri uri) {
+        if (null == uri || Uri.EMPTY == uri) {
+            throw new IllegalArgumentException("Given uri is not valid");
+        }
+        return checkRightsStatus(convertUriToPath(uri));
+    }
+
+    /**
+     * Check whether the given content has valid rights or not for specified action.
+     *
+     * @param path Path of the protected content
+     * @param action Action to perform
+     * @return Status of the rights for the protected content
+     * @see DrmStore.RightsStatus
+     */
+    public int checkRightsStatus(String path, int action) {
+        if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
+            throw new IllegalArgumentException("Given path or action is not valid");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _checkRightsStatus(mUniqueId, path, action);
+    }
+
+    /**
+     * Check whether the given content has valid rights or not for specified action.
+     *
+     * @param uri The content URI of the data
+     * @param action Action to perform
+     * @return Status of the rights for the protected content
+     * @see DrmStore.RightsStatus
+     */
+    public int checkRightsStatus(Uri uri, int action) {
+        if (null == uri || Uri.EMPTY == uri) {
+            throw new IllegalArgumentException("Given uri is not valid");
+        }
+        return checkRightsStatus(convertUriToPath(uri), action);
+    }
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param path Path of the protected content
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int removeRights(String path) {
+        if (null == path || path.equals("")) {
+            throw new IllegalArgumentException("Given path should be non null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _removeRights(mUniqueId, path);
+    }
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param uri The content URI of the data
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int removeRights(Uri uri) {
+        if (null == uri || Uri.EMPTY == uri) {
+            throw new IllegalArgumentException("Given uri is not valid");
+        }
+        return removeRights(convertUriToPath(uri));
+    }
+
+    /**
+     * Removes all the rights information of every plug-in associated with
+     * DRM framework. Will be used in master reset
+     *
+     * @return
+     *     ERROR_NONE for success
+     *     ERROR_UNKNOWN for failure
+     */
+    public int removeAllRights() {
+        if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        int result = ERROR_UNKNOWN;
+        if (null != mEventHandler) {
+            Message msg = mEventHandler.obtainMessage(ACTION_REMOVE_ALL_RIGHTS);
+            result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+        }
+        return result;
+    }
+
+    /**
+     * This API is for Forward Lock based DRM scheme.
+     * Each time the application tries to download a new DRM file
+     * which needs to be converted, then the application has to
+     * begin with calling this API.
+     *
+     * @param mimeType Description/MIME type of the input data packet
+     * @return convert ID which will be used for maintaining convert session.
+     */
+    public int openConvertSession(String mimeType) {
+        if (null == mimeType || mimeType.equals("")) {
+            throw new IllegalArgumentException("Path or the mimeType should be non null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _openConvertSession(mUniqueId, mimeType);
+    }
+
+    /**
+     * Accepts and converts the input data which is part of DRM file.
+     * The resultant converted data and the status is returned in the DrmConvertedInfo
+     * object. This method will be called each time there are new block
+     * of data received by the application.
+     *
+     * @param convertId Handle for the convert session
+     * @param inputData Input Data which need to be converted
+     * @return Return object contains the status of the data conversion,
+     *         the output converted data and offset. In this case the
+     *         application will ignore the offset information.
+     */
+    public DrmConvertedStatus convertData(int convertId, byte[] inputData) {
+        if (null == inputData || 0 >= inputData.length) {
+            throw new IllegalArgumentException("Given inputData should be non null");
+        } else if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _convertData(mUniqueId, convertId, inputData);
+    }
+
+    /**
+     * Informs the Drm Agent when there is no more data which need to be converted
+     * or when an error occurs. Upon successful conversion of the complete data,
+     * the agent will inform that where the header and body signature
+     * should be added. This signature appending is needed to integrity
+     * protect the converted file.
+     *
+     * @param convertId Handle for the convert session
+     * @return Return object contains the status of the data conversion,
+     *     the header and body signature data. It also informs
+     *     the application on which offset these signature data should be appended.
+     */
+    public DrmConvertedStatus closeConvertSession(int convertId) {
+        if (STATE_UNINITIALIZED == getState()) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _closeConvertSession(mUniqueId, convertId);
+    }
+
+    private int getState() {
+        return mCurrentState;
+    }
+
+    private int getEventType(int infoType) {
+        int eventType = -1;
+
+        switch (infoType) {
+        case DrmInfoRequest.TYPE_REGISTRATION_INFO:
+            eventType = DrmEvent.TYPE_REGISTERED;
+            break;
+        case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
+            eventType = DrmEvent.TYPE_UNREGISTERED;
+            break;
+        case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
+            eventType = DrmEvent.TYPE_RIGHTS_ACQUIRED;
+            break;
+        }
+        return eventType;
+    }
+
+    private int getErrorType(int infoType) {
+        int error = -1;
+
+        switch (infoType) {
+        case DrmInfoRequest.TYPE_REGISTRATION_INFO:
+            error = DrmErrorEvent.TYPE_REGISTRATION_FAILED;
+            break;
+        case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
+            error = DrmErrorEvent.TYPE_UNREGISTRATION_FAILED;
+            break;
+        case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
+            error = DrmErrorEvent.TYPE_RIGHTS_ACQUISITION_FAILED;
+            break;
+        }
+        return error;
+    }
+
+    /**
+     * This method expects uri in the following format
+     *     content://media/<table_name>/<row_index> (or)
+     *     file://sdcard/test.mp4
+     *
+     * Here <table_name> shall be "video" or "audio" or "images"
+     * <row_index> the index of the content in given table
+     */
+    private String convertUriToPath(Uri uri) {
+        String scheme = uri.getScheme();
+        if (null == scheme || scheme.equals("file")) {
+            return uri.getPath();
+        }
+        String[] projection = new String[] {MediaStore.MediaColumns.DATA};
+        Cursor cursor = mContext.getContentResolver().query(uri, projection, null, null, null);
+        if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
+            throw new IllegalArgumentException("Given Uri could not be found in media store");
+        }
+        int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+        String path = cursor.getString(pathIndex);
+        cursor.close();
+        return path;
+    }
+
+    // private native interfaces
+    private native int _loadPlugIns(int uniqueId, Object weak_this);
+
+    private native int _unloadPlugIns(int uniqueId);
+
+    private native void _installDrmEngine(int uniqueId, String engineFilepath);
+
+    private native ContentValues _getConstraints(int uniqueId, String path, int usage);
+
+    private native boolean _canHandle(int uniqueId, String path, String mimeType);
+
+    private native DrmInfoStatus _processDrmInfo(int uniqueId, DrmInfo drmInfo);
+
+    private native DrmInfo _acquireDrmInfo(int uniqueId, DrmInfoRequest drmInfoRequest);
+
+    private native int _saveRights(
+            int uniqueId, DrmRights drmRights, String rightsPath, String contentPath);
+
+    private native int _getDrmObjectType(int uniqueId, String path, String mimeType);
+
+    private native String _getOriginalMimeType(int uniqueId, String path);
+
+    private native int _checkRightsStatus(int uniqueId, String path, int action);
+
+    private native int _removeRights(int uniqueId, String path);
+
+    private native int _removeAllRights(int uniqueId);
+
+    private native int _openConvertSession(int uniqueId, String mimeType);
+
+    private native DrmConvertedStatus _convertData(
+            int uniqueId, int convertId, byte[] inputData);
+
+    private native DrmConvertedStatus _closeConvertSession(int uniqueId, int convertId);
+
+    private native DrmSupportInfo[] _getAllSupportInfo(int uniqueId);
+}
+
diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java
new file mode 100644
index 0000000..103af07
--- /dev/null
+++ b/drm/java/android/drm/DrmRights.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * This is an entity class which wraps the license information which was
+ * retrieved from the online DRM server.
+ *
+ * Caller can instantiate {@link DrmRights} by
+ * invoking {@link DrmRights#DrmRights(ProcessedData, String)}
+ * constructor by using the result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} interface.
+ * Caller can also instantiate {@link DrmRights} using the file path
+ * which contains rights information.
+ *
+ */
+public class DrmRights {
+    private byte[] mData;
+    private String mMimeType;
+    private String mAccountId = "_NO_USER";
+    private String mSubscriptionId = "";
+
+    /**
+     * constructor to create DrmRights object with given parameters
+     *
+     * @param rightsFilePath Path of the file containing rights data
+     * @param mimeType MIME type
+     */
+    public DrmRights(String rightsFilePath, String mimeType) {
+        File file = new File(rightsFilePath);
+        instantiate(file, mimeType);
+    }
+
+    /**
+     * constructor to create DrmRights object with given parameters
+     *
+     * @param rightsFilePath Path of the file containing rights data
+     * @param mimeType MIME type
+     * @param accountId Account Id of the user
+     */
+    public DrmRights(String rightsFilePath, String mimeType, String accountId) {
+        this(rightsFilePath, mimeType);
+
+        if (null != accountId && !accountId.equals("")) {
+            mAccountId = accountId;
+        }
+    }
+
+    /**
+     * constructor to create DrmRights object with given parameters
+     *
+     * @param rightsFilePath Path of the file containing rights data
+     * @param mimeType MIME type
+     * @param accountId Account Id of the user
+     * @param subscriptionId Subscription Id of the user
+     */
+    public DrmRights(
+            String rightsFilePath, String mimeType, String accountId, String subscriptionId) {
+        this(rightsFilePath, mimeType);
+
+        if (null != accountId && !accountId.equals("")) {
+            mAccountId = accountId;
+        }
+
+        if (null != subscriptionId && !subscriptionId.equals("")) {
+            mSubscriptionId = subscriptionId;
+        }
+    }
+
+    /**
+     * constructor to create DrmRights object with given parameters
+     *
+     * @param rightsFile File containing rights data
+     * @param mimeType MIME type
+     */
+    public DrmRights(File rightsFile, String mimeType) {
+        instantiate(rightsFile, mimeType);
+    }
+
+    private void instantiate(File rightsFile, String mimeType) {
+        try {
+            mData = DrmUtils.readBytes(rightsFile);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        mMimeType = mimeType;
+    }
+
+    /**
+     * constructor to create DrmRights object with given parameters
+     * The user can pass String or binary data<p>
+     * Usage:<p>
+     *        i)  String(e.g. data is instance of String):<br>
+     *            - new DrmRights(data.getBytes(), mimeType)<p>
+     *        ii) Binary data<br>
+     *            - new DrmRights(binaryData[], mimeType)<br>
+     *
+     * @param data Processed data
+     * @param mimeType MIME type
+     */
+    public DrmRights(ProcessedData data, String mimeType) {
+        mData = data.getData();
+
+        String accountId = data.getAccountId();
+        if (null != accountId && !accountId.equals("")) {
+            mAccountId = accountId;
+        }
+
+        String subscriptionId = data.getSubscriptionId();
+        if (null != subscriptionId && !subscriptionId.equals("")) {
+            mSubscriptionId = subscriptionId;
+        }
+
+        mMimeType = mimeType;
+    }
+
+    /**
+     * Returns the rights data associated with this object
+     *
+     * @return Rights data
+     */
+    public byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Returns the mimetype associated with this object
+     *
+     * @return MIME type
+     */
+    public String getMimeType() {
+        return mMimeType;
+    }
+
+    /**
+     * Returns the account-id associated with this object
+     *
+     * @return Account Id
+     */
+    public String getAccountId() {
+        return mAccountId;
+    }
+
+    /**
+     * Returns the subscription-id associated with this object
+     *
+     * @return Subscription Id
+     */
+    public String getSubscriptionId() {
+        return mSubscriptionId;
+    }
+
+    /**
+     * Returns whether this instance is valid or not
+     *
+     * @return
+     *     true if valid
+     *     false if invalid
+     */
+    /*package*/ boolean isValid() {
+        return (null != mMimeType && !mMimeType.equals("")
+                && null != mData && mData.length > 0);
+    }
+}
+
diff --git a/drm/java/android/drm/DrmStore.java b/drm/java/android/drm/DrmStore.java
new file mode 100644
index 0000000..44df90c
--- /dev/null
+++ b/drm/java/android/drm/DrmStore.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This class defines all the constants used by DRM framework
+ *
+ */
+public class DrmStore {
+    /**
+     * Columns representing drm constraints
+     */
+    public interface ConstraintsColumns {
+        /**
+         * The max repeat count
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MAX_REPEAT_COUNT = "max_repeat_count";
+
+        /**
+         * The remaining repeat count
+         * <P>Type: INTEGER</P>
+         */
+        public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
+
+        /**
+         * The time before which the protected file can not be played/viewed
+         * <P>Type: TEXT</P>
+         */
+        public static final String LICENSE_START_TIME = "license_start_time";
+
+        /**
+         * The time after which the protected file can not be played/viewed
+         * <P>Type: TEXT</P>
+         */
+        public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
+
+        /**
+         * The available time for license
+         * <P>Type: TEXT</P>
+         */
+        public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
+
+        /**
+         * The data stream for extended metadata
+         * <P>Type: TEXT</P>
+         */
+        public static final String EXTENDED_METADATA = "extended_metadata";
+    }
+
+    /**
+     * Defines constants related to DRM types
+     */
+    public static class DrmObjectType {
+        /**
+         * Field specifies the unknown type
+         */
+        public static final int UNKNOWN = 0x00;
+        /**
+         * Field specifies the protected content type
+         */
+        public static final int CONTENT = 0x01;
+        /**
+         * Field specifies the rights information
+         */
+        public static final int RIGHTS_OBJECT = 0x02;
+        /**
+         * Field specifies the trigger information
+         */
+        public static final int TRIGGER_OBJECT = 0x03;
+    }
+
+    /**
+     * Defines constants related to playback
+     */
+    public static class Playback {
+        /**
+         * Constant field signifies playback start
+         */
+        public static final int START = 0x00;
+        /**
+         * Constant field signifies playback stop
+         */
+        public static final int STOP = 0x01;
+        /**
+         * Constant field signifies playback paused
+         */
+        public static final int PAUSE = 0x02;
+        /**
+         * Constant field signifies playback resumed
+         */
+        public static final int RESUME = 0x03;
+
+        /* package */ static boolean isValid(int playbackStatus) {
+            boolean isValid = false;
+
+            switch (playbackStatus) {
+                case START:
+                case STOP:
+                case PAUSE:
+                case RESUME:
+                    isValid = true;
+            }
+            return isValid;
+        }
+    }
+
+    /**
+     * Defines actions that can be performed on protected content
+     */
+    public static class Action {
+        /**
+         * Constant field signifies that the default action
+         */
+        public static final int DEFAULT = 0x00;
+        /**
+         * Constant field signifies that the content can be played
+         */
+        public static final int PLAY = 0x01;
+        /**
+         * Constant field signifies that the content can be set as ring tone
+         */
+        public static final int RINGTONE = 0x02;
+        /**
+         * Constant field signifies that the content can be transfered
+         */
+        public static final int TRANSFER = 0x03;
+        /**
+         * Constant field signifies that the content can be set as output
+         */
+        public static final int OUTPUT = 0x04;
+        /**
+         * Constant field signifies that preview is allowed
+         */
+        public static final int PREVIEW = 0x05;
+        /**
+         * Constant field signifies that the content can be executed
+         */
+        public static final int EXECUTE = 0x06;
+        /**
+         * Constant field signifies that the content can displayed
+         */
+        public static final int DISPLAY = 0x07;
+
+        /* package */ static boolean isValid(int action) {
+            boolean isValid = false;
+
+            switch (action) {
+                case DEFAULT:
+                case PLAY:
+                case RINGTONE:
+                case TRANSFER:
+                case OUTPUT:
+                case PREVIEW:
+                case EXECUTE:
+                case DISPLAY:
+                    isValid = true;
+            }
+            return isValid;
+        }
+    }
+
+    /**
+     * Defines constants related to status of the rights
+     */
+    public static class RightsStatus {
+        /**
+         * Constant field signifies that the rights are valid
+         */
+        public static final int RIGHTS_VALID = 0x00;
+        /**
+         * Constant field signifies that the rights are invalid
+         */
+        public static final int RIGHTS_INVALID = 0x01;
+        /**
+         * Constant field signifies that the rights are expired for the content
+         */
+        public static final int RIGHTS_EXPIRED = 0x02;
+        /**
+         * Constant field signifies that the rights are not acquired for the content
+         */
+        public static final int RIGHTS_NOT_ACQUIRED = 0x03;
+    }
+}
+
diff --git a/drm/java/android/drm/DrmSupportInfo.java b/drm/java/android/drm/DrmSupportInfo.java
new file mode 100644
index 0000000..0886af8
--- /dev/null
+++ b/drm/java/android/drm/DrmSupportInfo.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * This is an entity class which wraps the capability of each plug-in,
+ * such as mimetype's and file suffixes it could handle.
+ *
+ * Plug-in developer could return the capability of the plugin by passing
+ * {@link DrmSupportInfo} instance.
+ *
+ */
+public class DrmSupportInfo {
+    private final ArrayList<String> mFileSuffixList = new ArrayList<String>();
+    private final ArrayList<String> mMimeTypeList = new ArrayList<String>();
+    private String mDescription = "";
+
+    /**
+     * Add the mime-type to the support info such that respective plug-in is
+     * capable of handling the given mime-type.
+     *
+     * @param mimeType MIME type
+     */
+    public void addMimeType(String mimeType) {
+        mMimeTypeList.add(mimeType);
+    }
+
+    /**
+     * Add the file suffix to the support info such that respective plug-in is
+     * capable of handling the given file suffix.
+     *
+     * @param fileSuffix File suffix which can be handled
+     */
+    public void addFileSuffix(String fileSuffix) {
+        mFileSuffixList.add(fileSuffix);
+    }
+
+    /**
+     * Returns the iterator to walk to through mime types of this object
+     *
+     * @return Iterator object
+     */
+    public Iterator<String> getMimeTypeIterator() {
+        return mMimeTypeList.iterator();
+    }
+
+    /**
+     * Returns the iterator to walk to through file suffixes of this object
+     *
+     * @return Iterator object
+     */
+    public Iterator<String> getFileSuffixIterator() {
+        return mFileSuffixList.iterator();
+    }
+
+    /**
+     * Set the unique description about the plugin
+     *
+     * @param description Unique description
+     */
+    public void setDescription(String description) {
+        if (null != description) {
+            mDescription = description;
+        }
+    }
+
+    /**
+     * Returns the unique description associated with the plugin
+     *
+     * @return Unique description
+     */
+    public String getDescriprition() {
+        return mDescription;
+    }
+
+    /**
+     * Overridden hash code implementation
+     *
+     * @return Hash code value
+     */
+    public int hashCode() {
+        return mFileSuffixList.hashCode() + mMimeTypeList.hashCode() + mDescription.hashCode();
+    }
+
+    /**
+     * Overridden equals implementation
+     *
+     * @param object The object to be compared
+     * @return
+     *     true if equal
+     *     false if not equal
+     */
+    public boolean equals(Object object) {
+        boolean result = false;
+
+        if (object instanceof DrmSupportInfo) {
+            result = mFileSuffixList.equals(((DrmSupportInfo) object).mFileSuffixList) &&
+                    mMimeTypeList.equals(((DrmSupportInfo) object).mMimeTypeList) &&
+                    mDescription.equals(((DrmSupportInfo) object).mDescription);
+        }
+        return result;
+    }
+
+    /**
+     * Returns whether given mime-type is supported or not
+     *
+     * @param mimeType MIME type
+     * @return
+     *     true if mime type is supported
+     *     false if mime type is not supported
+     */
+    /* package */ boolean isSupportedMimeType(String mimeType) {
+        if (null != mimeType && !mimeType.equals("")) {
+            for (int i = 0; i < mMimeTypeList.size(); i++) {
+                String completeMimeType = mMimeTypeList.get(i);
+                if (completeMimeType.startsWith(mimeType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether given file suffix is supported or not
+     *
+     * @param fileSuffix File suffix
+     * @return
+     *     true - if file suffix is supported
+     *     false - if file suffix is not supported
+     */
+    /* package */ boolean isSupportedFileSuffix(String fileSuffix) {
+        return mFileSuffixList.contains(fileSuffix);
+    }
+}
+
diff --git a/drm/java/android/drm/DrmUtils.java b/drm/java/android/drm/DrmUtils.java
new file mode 100644
index 0000000..5e5397c
--- /dev/null
+++ b/drm/java/android/drm/DrmUtils.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * The utility class used in the DRM Framework. This inclueds APIs for file operations
+ * and ExtendedMetadataParser for parsing extended metadata BLOB in DRM constraints.
+ *
+ */
+public class DrmUtils {
+    /* Should be used when we need to read from local file */
+    /* package */ static byte[] readBytes(String path) throws IOException {
+        File file = new File(path);
+        return readBytes(file);
+    }
+
+    /* Should be used when we need to read from local file */
+    /* package */ static byte[] readBytes(File file) throws IOException {
+        FileInputStream inputStream = new FileInputStream(file);
+        BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
+        byte[] data = null;
+
+        try {
+            int length = bufferedStream.available();
+            if (length > 0) {
+                data = new byte[length];
+                // read the entire data
+                bufferedStream.read(data);
+             }
+        } finally {
+            quiteDispose(bufferedStream);
+            quiteDispose(inputStream);
+        }
+        return data;
+    }
+
+    /* package */ static void writeToFile(final String path, byte[] data) throws IOException {
+        /* check for invalid inputs */
+        FileOutputStream outputStream = null;
+
+        if (null != path && null != data) {
+            try {
+                outputStream = new FileOutputStream(path);
+                outputStream.write(data);
+            } finally {
+                quiteDispose(outputStream);
+            }
+        }
+    }
+
+    /* package */ static void removeFile(String path) throws IOException {
+        File file = new File(path);
+        file.delete();
+    }
+
+    private static void quiteDispose(InputStream stream) {
+        try {
+            if (null != stream) {
+                stream.close();
+            }
+        } catch (IOException e) {
+            // no need to care, at least as of now
+        }
+    }
+
+    private static void quiteDispose(OutputStream stream) {
+        try {
+            if (null != stream) {
+                stream.close();
+            }
+        } catch (IOException e) {
+            // no need to care
+        }
+    }
+
+    /**
+     * Get an instance of ExtendedMetadataParser to be used for parsing
+     * extended metadata BLOB in DRM constraints. <br>
+     *
+     * extendedMetadata BLOB is retrieved by specifing
+     * key DrmStore.ConstraintsColumns.EXTENDED_METADATA.
+     *
+     * @param extendedMetadata BLOB in which key-value pairs of extended metadata are embedded.
+     *
+     */
+    public static ExtendedMetadataParser getExtendedMetadataParser(byte[] extendedMetadata) {
+        return new ExtendedMetadataParser(extendedMetadata);
+    }
+
+    /**
+     * Utility parser to parse the extended meta-data embedded inside DRM constraints<br><br>
+     *
+     * Usage example<br>
+     * byte[] extendedMetadata<br>
+     * &nbsp;&nbsp;&nbsp;&nbsp; =
+     *         constraints.getAsByteArray(DrmStore.ConstraintsColumns.EXTENDED_METADATA);<br>
+     * ExtendedMetadataParser parser = getExtendedMetadataParser(extendedMetadata);<br>
+     * Iterator keyIterator = parser.keyIterator();<br>
+     * while (keyIterator.hasNext()) {<br>
+     *     &nbsp;&nbsp;&nbsp;&nbsp;String extendedMetadataKey = keyIterator.next();<br>
+     *     &nbsp;&nbsp;&nbsp;&nbsp;String extendedMetadataValue =
+     *             parser.get(extendedMetadataKey);<br>
+     * }
+     */
+    public static class ExtendedMetadataParser {
+        HashMap<String, String> mMap = new HashMap<String, String>();
+
+        private int readByte(byte[] constraintData, int arrayIndex) {
+            //Convert byte[] into int.
+            return (int)constraintData[arrayIndex];
+        }
+
+        private String readMultipleBytes(
+                byte[] constraintData, int numberOfBytes, int arrayIndex) {
+            byte[] returnBytes = new byte[numberOfBytes];
+            for (int j = arrayIndex, i = 0; j < arrayIndex + numberOfBytes; j++,i++) {
+                returnBytes[i] = constraintData[j];
+            }
+            return new String(returnBytes);
+        }
+
+        /*
+         * This will parse the following format
+         * KeyLengthValueLengthKeyValueKeyLength1ValueLength1Key1Value1..\0
+         */
+        private ExtendedMetadataParser(byte[] constraintData) {
+            //Extract KeyValue Pair Info, till terminator occurs.
+            int index = 0;
+
+            while (index < constraintData.length) {
+                //Parse Key Length
+                int keyLength = readByte(constraintData, index);
+                index++;
+
+                //Parse Value Length
+                int valueLength = readByte(constraintData, index);
+                index++;
+
+                //Fetch key
+                String strKey = readMultipleBytes(constraintData, keyLength, index);
+                index += keyLength;
+
+                //Fetch Value
+                String strValue = readMultipleBytes(constraintData, valueLength, index);
+                index += valueLength;
+                mMap.put(strKey, strValue);
+            }
+        }
+
+        public Iterator<String> iterator() {
+            return mMap.values().iterator();
+        }
+
+        public Iterator<String> keyIterator() {
+            return mMap.keySet().iterator();
+        }
+
+        public String get(String key) {
+            return mMap.get(key);
+        }
+    }
+}
+
diff --git a/drm/java/android/drm/ProcessedData.java b/drm/java/android/drm/ProcessedData.java
new file mode 100644
index 0000000..579264f
--- /dev/null
+++ b/drm/java/android/drm/ProcessedData.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.drm;
+
+/**
+ * This is an entity class which wraps the result of transaction between
+ * device and online DRM server by using {@link DrmManagerClient#processDrmInfo(DrmInfo)}
+ *
+ * In license acquisition scenario this class would hold the binary data
+ * of rights information.
+ *
+ */
+public class ProcessedData {
+    private final byte[] mData;
+    private String mAccountId = "_NO_USER";
+    private String mSubscriptionId = "";
+
+    /**
+     * constructor to create ProcessedData object with given parameters
+     *
+     * @param data Rights data
+     * @param accountId Account Id of the user
+     */
+    /* package */ ProcessedData(byte[] data, String accountId) {
+        mData = data;
+        mAccountId = accountId;
+    }
+
+    /**
+     * constructor to create ProcessedData object with given parameters
+     *
+     * @param data Rights data
+     * @param accountId Account Id of the user
+     * @param subscriptionId Subscription Id of the user
+     */
+    /* package */ ProcessedData(byte[] data, String accountId, String subscriptionId) {
+        mData = data;
+        mAccountId = accountId;
+        mSubscriptionId = subscriptionId;
+    }
+
+    /**
+     * Returns the processed data as a result.
+     *
+     * @return Rights data associated
+     */
+    public byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Returns the account-id associated with this object
+     *
+     * @return Account Id associated
+     */
+    public String getAccountId() {
+        return mAccountId;
+    }
+
+    /**
+     * Returns the subscription-id associated with this object
+     *
+     * @return Subscription Id associated
+     */
+    public String getSubscriptionId() {
+        return mSubscriptionId;
+    }
+}
+
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
new file mode 100644
index 0000000..b65e4da
--- /dev/null
+++ b/drm/jni/Android.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    android_drm_DrmManagerClient.cpp
+
+LOCAL_MODULE:= libdrmframework_jni
+
+LOCAL_SHARED_LIBRARIES := \
+    libdrmframework \
+    libutils \
+    libandroid_runtime \
+    libnativehelper \
+    libbinder
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES :=
+
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE) \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/plugins/common/include \
+    $(TOP)/frameworks/base/include
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
new file mode 100644
index 0000000..6158b66
--- /dev/null
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmManager-JNI"
+#include <utils/Log.h>
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <drm/DrmInfo.h>
+#include <drm/DrmRights.h>
+#include <drm/DrmInfoEvent.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmConvertedStatus.h>
+#include <drm/drm_framework_common.h>
+
+#include <DrmManagerClientImpl.h>
+
+using namespace android;
+
+/**
+ * Utility class used to extract the value from the provided java object.
+ * May need to add some utility function to create java object.
+ */
+class Utility {
+public:
+    static String8 getStringValue(JNIEnv* env, jobject object, const char* fieldName);
+
+    static char* getByteArrayValue(
+            JNIEnv* env, jobject object, const char* fieldName, int* dataLength);
+
+    static char* getByteArrayValue(
+            JNIEnv* env, jbyteArray byteArray, int* dataLength);
+
+    static String8 getStringValue(JNIEnv* env, jstring string);
+
+    static int getIntValue(JNIEnv* env, jobject object, const char* fieldName);
+};
+
+String8 Utility::getStringValue(JNIEnv* env, jobject object, const char* fieldName) {
+    String8 dataString("");
+
+    /* Look for the instance field with the name fieldName */
+    jfieldID fieldID
+        = env->GetFieldID(env->GetObjectClass(object), fieldName , "Ljava/lang/String;");
+
+    if (NULL != fieldID) {
+        jstring valueString = (jstring) env->GetObjectField(object, fieldID);
+
+        if (NULL != valueString && valueString != env->NewStringUTF("")) {
+            char* bytes = const_cast< char* > (env->GetStringUTFChars(valueString, NULL));
+
+            const int length = strlen(bytes) + 1;
+            char *data = new char[length];
+            strncpy(data, bytes, length);
+            dataString = String8(data);
+
+            env->ReleaseStringUTFChars(valueString, bytes);
+            delete [] data; data = NULL;
+        } else {
+            LOGV("Failed to retrieve the data from the field %s", fieldName);
+        }
+    }
+    return dataString;
+}
+
+String8 Utility::getStringValue(JNIEnv* env, jstring string) {
+    String8 dataString("");
+
+    if (NULL != string && string != env->NewStringUTF("")) {
+        char* bytes = const_cast< char* > (env->GetStringUTFChars(string, NULL));
+
+        const int length = strlen(bytes) + 1;
+        char *data = new char[length];
+        strncpy(data, bytes, length);
+        dataString = String8(data);
+
+        env->ReleaseStringUTFChars(string, bytes);
+        delete [] data; data = NULL;
+    }
+    return dataString;
+}
+
+char* Utility::getByteArrayValue(
+            JNIEnv* env, jobject object, const char* fieldName, int* dataLength) {
+    char* data = NULL;
+    *dataLength = 0;
+
+    jfieldID fieldID = env->GetFieldID(env->GetObjectClass(object), fieldName , "[B");
+
+    if (NULL != fieldID) {
+        jbyteArray byteArray = (jbyteArray) env->GetObjectField(object, fieldID);
+        if (NULL != byteArray) {
+            jint length = env->GetArrayLength(byteArray);
+
+            *dataLength = length;
+            if (0 < *dataLength) {
+                data = new char[length];
+                env->GetByteArrayRegion(byteArray, (jint)0, length, (jbyte *) data);
+            }
+        }
+    }
+    return data;
+}
+
+char* Utility::getByteArrayValue(JNIEnv* env, jbyteArray byteArray, int* dataLength) {
+    char* data = NULL;
+    if (NULL != byteArray) {
+        jint length = env->GetArrayLength(byteArray);
+
+        *dataLength = length;
+        if (0 < *dataLength) {
+            data = new char[length];
+            env->GetByteArrayRegion(byteArray, (jint)0, length, (jbyte *) data);
+        }
+    }
+    return data;
+}
+
+int Utility::getIntValue(JNIEnv* env, jobject object, const char* fieldName) {
+    jfieldID fieldID;
+    int intValue = -1;
+
+    /* Get a reference to obj’s class */
+    jclass clazz = env->GetObjectClass(object);
+    /* Look for the instance field with the name fieldName */
+    fieldID = env->GetFieldID(clazz, fieldName , "I");
+
+    if (NULL != fieldID) {
+        intValue = (int) env->GetIntField(object, fieldID);
+    }
+
+    return intValue;
+}
+
+class JNIOnInfoListener : public DrmManagerClient::OnInfoListener {
+public:
+    JNIOnInfoListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
+
+    virtual ~JNIOnInfoListener();
+    void onInfo(const DrmInfoEvent& event);
+
+private:
+    JNIOnInfoListener();
+    jclass mClass;
+    jobject mObject;
+};
+
+JNIOnInfoListener::JNIOnInfoListener(JNIEnv* env, jobject thiz, jobject weak_thiz) {
+    jclass clazz = env->GetObjectClass(thiz);
+
+    if (clazz == NULL) {
+        LOGE("Can't find android/drm/DrmManagerClient");
+        jniThrowException(env, "java/lang/Exception", NULL);
+        return;
+    }
+    mClass = (jclass)env->NewGlobalRef(clazz);
+    mObject  = env->NewGlobalRef(weak_thiz);
+}
+
+JNIOnInfoListener::~JNIOnInfoListener() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mObject);
+    env->DeleteGlobalRef(mClass);
+}
+
+void JNIOnInfoListener::onInfo(const DrmInfoEvent& event) {
+    jint uniqueId = event.getUniqueId();
+    jint type = event.getType();
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jstring message = env->NewStringUTF(event.getMessage().string());
+    LOGV("JNIOnInfoListener::onInfo => %d | %d | %s", uniqueId, type, event.getMessage().string());
+
+    env->CallStaticVoidMethod(
+            mClass,
+            env->GetStaticMethodID(mClass, "notify", "(Ljava/lang/Object;IILjava/lang/String;)V"),
+            mObject, uniqueId, type, message);
+}
+
+static Mutex sLock;
+
+static sp<DrmManagerClientImpl> setDrmManagerClientImpl(
+            JNIEnv* env, jobject thiz, const sp<DrmManagerClientImpl>& client) {
+    Mutex::Autolock l(sLock);
+    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
+    jfieldID fieldId = env->GetFieldID(clazz, "mNativeContext", "I");
+
+    sp<DrmManagerClientImpl> old = (DrmManagerClientImpl*)env->GetIntField(thiz, fieldId);
+    if (client.get()) {
+        client->incStrong(thiz);
+    }
+    if (old != 0) {
+        old->decStrong(thiz);
+    }
+    env->SetIntField(thiz, fieldId, (int)client.get());
+    return old;
+}
+
+static sp<DrmManagerClientImpl> getDrmManagerClientImpl(JNIEnv* env, jobject thiz) {
+    Mutex::Autolock l(sLock);
+    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
+    jfieldID fieldId = env->GetFieldID(clazz, "mNativeContext", "I");
+
+    DrmManagerClientImpl* const client = (DrmManagerClientImpl*)env->GetIntField(thiz, fieldId);
+    return sp<DrmManagerClientImpl>(client);
+}
+
+static jint android_drm_DrmManagerClient_loadPlugIns(
+        JNIEnv* env, jobject thiz, jint uniqueId, jobject weak_thiz) {
+    LOGV("load plugins - Enter");
+
+    sp<DrmManagerClientImpl> drmManager = DrmManagerClientImpl::create(&uniqueId);
+
+    // Set the listener to DrmManager
+    sp<DrmManagerClient::OnInfoListener> listener = new JNIOnInfoListener(env, thiz, weak_thiz);
+    drmManager->setOnInfoListener(uniqueId, listener);
+
+    setDrmManagerClientImpl(env, thiz, drmManager);
+
+    LOGV("load plugins - Exit");
+    return getDrmManagerClientImpl(env, thiz)->loadPlugIns(uniqueId);
+}
+
+static jint android_drm_DrmManagerClient_unloadPlugIns(JNIEnv* env, jobject thiz, jint uniqueId) {
+    LOGV("unload plugins - Enter");
+    sp<DrmManagerClientImpl> client = getDrmManagerClientImpl(env, thiz);
+
+    DrmManagerClientImpl::remove(uniqueId);
+    int result = client->unloadPlugIns(uniqueId);
+    if (DRM_NO_ERROR == result) {
+        client->setOnInfoListener(uniqueId, NULL);
+
+        sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
+        if (oldClient != NULL) {
+            oldClient->setOnInfoListener(uniqueId, NULL);
+        }
+    }
+    LOGV("unload plugins - Exit");
+    return result;
+}
+
+static jobject android_drm_DrmManagerClient_getConstraintsFromContent(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring jpath, jint usage) {
+    LOGV("GetConstraints - Enter");
+
+    const String8 pathString = Utility::getStringValue(env, jpath);
+    DrmConstraints* pConstraints
+        = getDrmManagerClientImpl(env, thiz)->getConstraints(uniqueId, &pathString, usage);
+
+    jclass localRef = env->FindClass("android/content/ContentValues");
+    jobject constraints = NULL;
+
+    if (NULL != localRef && NULL != pConstraints) {
+        // Get the constructor id
+        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "()V");
+        // create the java DrmConstraints object
+        constraints = env->NewObject(localRef, constructorId);
+
+        DrmConstraints::KeyIterator keyIt = pConstraints->keyIterator();
+
+        while (keyIt.hasNext()) {
+            String8 key = keyIt.next();
+
+            // insert the entry<constraintKey, constraintValue> to newly created java object
+            if (DrmConstraints::EXTENDED_METADATA == key) {
+                const char* value = pConstraints->getAsByteArray(&key);
+                if (NULL != value) {
+                    jbyteArray dataArray = env->NewByteArray(strlen(value));
+                    env->SetByteArrayRegion(dataArray, 0, strlen(value), (jbyte*)value);
+                    env->CallVoidMethod(
+                        constraints, env->GetMethodID(localRef, "put", "(Ljava/lang/String;[B)V"),
+                                     env->NewStringUTF(key.string()), dataArray);
+                }
+            } else {
+                String8 value = pConstraints->get(key);
+                env->CallVoidMethod(
+                    constraints,
+                    env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V"),
+                env->NewStringUTF(key.string()), env->NewStringUTF(value.string()));
+            }
+        }
+    }
+
+    delete pConstraints; pConstraints = NULL;
+    LOGV("GetConstraints - Exit");
+    return constraints;
+}
+
+static jobjectArray android_drm_DrmManagerClient_getAllSupportInfo(
+            JNIEnv* env, jobject thiz, jint uniqueId) {
+    LOGV("GetAllSupportInfo - Enter");
+    DrmSupportInfo* drmSupportInfoArray = NULL;
+
+    int length = 0;
+    getDrmManagerClientImpl(env, thiz)->getAllSupportInfo(uniqueId, &length, &drmSupportInfoArray);
+
+    jclass clazz = env->FindClass("android/drm/DrmSupportInfo");
+
+    jobjectArray array = (jobjectArray)env->NewObjectArray(length, clazz, NULL);
+
+    for (int i = 0; i < length; i++) {
+        DrmSupportInfo info = drmSupportInfoArray[i];
+
+        jobject drmSupportInfo = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));
+
+        jmethodID addMimeTypeId
+            = env->GetMethodID(clazz, "addMimeType", "(Ljava/lang/String;)V");
+        jmethodID addFileSuffixId
+            = env->GetMethodID(clazz, "addFileSuffix", "(Ljava/lang/String;)V");
+
+        env->CallVoidMethod(
+            drmSupportInfo, env->GetMethodID(clazz, "setDescription", "(Ljava/lang/String;)V"),
+            env->NewStringUTF(info.getDescription().string()));
+
+        DrmSupportInfo::MimeTypeIterator iterator = info.getMimeTypeIterator();
+        while (iterator.hasNext()) {
+            String8  value = iterator.next();
+            env->CallVoidMethod(drmSupportInfo, addMimeTypeId, env->NewStringUTF(value.string()));
+        }
+
+        DrmSupportInfo::FileSuffixIterator it = info.getFileSuffixIterator();
+        while (it.hasNext()) {
+            String8 value = it.next();
+            env->CallVoidMethod(
+                drmSupportInfo, addFileSuffixId, env->NewStringUTF(value.string()));
+        }
+
+        env->SetObjectArrayElement(array, i, drmSupportInfo);
+    }
+
+    delete [] drmSupportInfoArray; drmSupportInfoArray = NULL;
+    LOGV("GetAllSupportInfo - Exit");
+    return array;
+}
+
+static void android_drm_DrmManagerClient_installDrmEngine(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring engineFilePath) {
+    LOGV("installDrmEngine - Enter");
+    //getDrmManagerClient(env, thiz)
+    //  ->installDrmEngine(uniqueId, Utility::getStringValue(env, engineFilePath));
+    LOGV("installDrmEngine - Exit");
+}
+
+static jint android_drm_DrmManagerClient_saveRights(
+            JNIEnv* env, jobject thiz, jint uniqueId,
+            jobject drmRights, jstring rightsPath, jstring contentPath) {
+    LOGV("saveRights - Enter");
+    int result = DRM_ERROR_UNKNOWN;
+    int dataLength = 0;
+    char* mData =  Utility::getByteArrayValue(env, drmRights, "mData", &dataLength);
+
+    if (NULL != mData) {
+        DrmRights rights(DrmBuffer(mData, dataLength),
+                Utility::getStringValue(env, drmRights, "mMimeType"),
+                Utility::getStringValue(env, drmRights, "mAccountId"),
+                Utility::getStringValue(env, drmRights, "mSubscriptionId"));
+        result = getDrmManagerClientImpl(env, thiz)
+            ->saveRights(uniqueId, rights, Utility::getStringValue(env, rightsPath),
+                                Utility::getStringValue(env, contentPath));
+    }
+
+    delete mData; mData = NULL;
+    LOGV("saveRights - Exit");
+    return result;
+}
+
+static jboolean android_drm_DrmManagerClient_canHandle(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
+    LOGV("canHandle - Enter");
+    jboolean result
+        = getDrmManagerClientImpl(env, thiz)
+            ->canHandle(uniqueId, Utility::getStringValue(env, path),
+                    Utility::getStringValue(env, mimeType));
+    LOGV("canHandle - Exit");
+    return result;
+}
+
+static jobject android_drm_DrmManagerClient_processDrmInfo(
+            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoObject) {
+    LOGV("processDrmInfo - Enter");
+    int dataLength = 0;
+    const String8 mMimeType =  Utility::getStringValue(env, drmInfoObject, "mMimeType");
+    char* mData =  Utility::getByteArrayValue(env, drmInfoObject, "mData", &dataLength);
+    int mInfoType = Utility::getIntValue(env, drmInfoObject, "mInfoType");
+
+    const DrmBuffer buffer(mData, dataLength);
+    DrmInfo drmInfo(mInfoType, buffer, mMimeType);
+
+    jclass clazz = env->FindClass("android/drm/DrmInfo");
+    jobject keyIterator
+        = env->CallObjectMethod(drmInfoObject,
+                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
+
+    jmethodID hasNextId = env->GetMethodID(env->FindClass("java/util/Iterator"), "hasNext", "()Z");
+
+    while (env->CallBooleanMethod(keyIterator, hasNextId)) {
+        jstring key = (jstring) env->CallObjectMethod(keyIterator,
+                env->GetMethodID(env->FindClass("java/util/Iterator"),
+                "next", "()Ljava/lang/Object;"));
+
+        jobject valueObject = env->CallObjectMethod(drmInfoObject,
+                env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;"), key);
+
+        jstring valString = NULL;
+        if (NULL != valueObject) {
+            valString = (jstring) env->CallObjectMethod(valueObject,
+                env->GetMethodID(env->FindClass("java/lang/Object"),
+                "toString", "()Ljava/lang/String;"));
+        }
+
+        String8 keyString = Utility::getStringValue(env, key);
+        String8 valueString = Utility::getStringValue(env, valString);
+        LOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
+
+        drmInfo.put(keyString, valueString);
+    }
+
+    DrmInfoStatus* pDrmInfoStatus
+        = getDrmManagerClientImpl(env, thiz)->processDrmInfo(uniqueId, &drmInfo);
+
+    jclass localRef = env->FindClass("android/drm/DrmInfoStatus");
+    jobject drmInfoStatus = NULL;
+
+    if (NULL != localRef && NULL != pDrmInfoStatus) {
+        int statusCode = pDrmInfoStatus->statusCode;
+
+        jbyteArray dataArray = NULL;
+        if (NULL != pDrmInfoStatus->drmBuffer) {
+            int length = pDrmInfoStatus->drmBuffer->length;
+            dataArray = env->NewByteArray(length);
+            env->SetByteArrayRegion(
+                dataArray, 0, length, (jbyte*) pDrmInfoStatus->drmBuffer->data);
+
+            delete [] pDrmInfoStatus->drmBuffer->data;
+            delete pDrmInfoStatus->drmBuffer; pDrmInfoStatus->drmBuffer = NULL;
+        }
+        jclass clazz = env->FindClass("android/drm/ProcessedData");
+        jmethodID constructorId
+            = env->GetMethodID(clazz, "<init>", "([BLjava/lang/String;Ljava/lang/String;)V");
+        jobject processedData = env->NewObject(clazz, constructorId, dataArray,
+                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::ACCOUNT_ID)).string()),
+                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::SUBSCRIPTION_ID)).string()));
+
+        constructorId
+            = env->GetMethodID(localRef,
+                "<init>", "(ILandroid/drm/ProcessedData;Ljava/lang/String;)V");
+
+        drmInfoStatus = env->NewObject(localRef, constructorId, statusCode, processedData,
+                                env->NewStringUTF(pDrmInfoStatus->mimeType.string()));
+    }
+
+    delete mData; mData = NULL;
+    delete pDrmInfoStatus; pDrmInfoStatus = NULL;
+
+    LOGV("processDrmInfo - Exit");
+    return drmInfoStatus;
+}
+
+static jobject android_drm_DrmManagerClient_acquireDrmInfo(
+            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoRequest) {
+    LOGV("acquireDrmInfo Enter");
+    const String8 mMimeType =  Utility::getStringValue(env, drmInfoRequest, "mMimeType");
+    int mInfoType = Utility::getIntValue(env, drmInfoRequest, "mInfoType");
+
+    DrmInfoRequest drmInfoReq(mInfoType, mMimeType);
+
+    jclass clazz = env->FindClass("android/drm/DrmInfoRequest");
+    jobject keyIterator
+        = env->CallObjectMethod(drmInfoRequest,
+                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
+
+    jmethodID hasNextId = env->GetMethodID(env->FindClass("java/util/Iterator"), "hasNext", "()Z");
+
+    while (env->CallBooleanMethod(keyIterator, hasNextId)) {
+        jstring key
+            = (jstring) env->CallObjectMethod(keyIterator,
+                env->GetMethodID(env->FindClass("java/util/Iterator"),
+                                "next", "()Ljava/lang/Object;"));
+
+        jstring value = (jstring) env->CallObjectMethod(drmInfoRequest,
+                env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;"), key);
+
+        String8 keyString = Utility::getStringValue(env, key);
+        String8 valueString = Utility::getStringValue(env, value);
+        LOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
+
+        drmInfoReq.put(keyString, valueString);
+    }
+
+    DrmInfo* pDrmInfo = getDrmManagerClientImpl(env, thiz)->acquireDrmInfo(uniqueId, &drmInfoReq);
+
+    jobject drmInfoObject = NULL;
+
+    if (NULL != pDrmInfo) {
+        jclass localRef = env->FindClass("android/drm/DrmInfo");
+
+        if (NULL != localRef) {
+            int length = pDrmInfo->getData().length;
+
+            jbyteArray dataArray = env->NewByteArray(length);
+            env->SetByteArrayRegion(dataArray, 0, length, (jbyte*)pDrmInfo->getData().data);
+
+            drmInfoObject
+                = env->NewObject(localRef,
+                    env->GetMethodID(localRef, "<init>", "(I[BLjava/lang/String;)V"),
+                    mInfoType, dataArray, env->NewStringUTF(pDrmInfo->getMimeType().string()));
+
+            DrmInfo::KeyIterator it = pDrmInfo->keyIterator();
+            jmethodID putMethodId
+                = env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/Object;)V");
+
+            while (it.hasNext()) {
+                String8 key = it.next();
+                String8 value = pDrmInfo->get(key);
+
+                env->CallVoidMethod(drmInfoObject, putMethodId,
+                    env->NewStringUTF(key.string()), env->NewStringUTF(value.string()));
+            }
+        }
+        delete [] pDrmInfo->getData().data;
+    }
+
+    delete pDrmInfo; pDrmInfo = NULL;
+
+    LOGV("acquireDrmInfo Exit");
+    return drmInfoObject;
+}
+
+static jint android_drm_DrmManagerClient_getDrmObjectType(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
+    LOGV("getDrmObjectType Enter");
+    int drmObjectType
+        = getDrmManagerClientImpl(env, thiz)
+            ->getDrmObjectType(uniqueId, Utility::getStringValue(env, path),
+                                Utility::getStringValue(env, mimeType));
+    LOGV("getDrmObjectType Exit");
+    return drmObjectType;
+}
+
+static jstring android_drm_DrmManagerClient_getOriginalMimeType(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
+    LOGV("getOriginalMimeType Enter");
+    String8 mimeType
+        = getDrmManagerClientImpl(env, thiz)
+            ->getOriginalMimeType(uniqueId, Utility::getStringValue(env, path));
+    LOGV("getOriginalMimeType Exit");
+    return env->NewStringUTF(mimeType.string());
+}
+
+static jint android_drm_DrmManagerClient_checkRightsStatus(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, int action) {
+    LOGV("getOriginalMimeType Enter");
+    int rightsStatus
+        = getDrmManagerClientImpl(env, thiz)
+            ->checkRightsStatus(uniqueId, Utility::getStringValue(env, path), action);
+    LOGV("getOriginalMimeType Exit");
+    return rightsStatus;
+}
+
+static jint android_drm_DrmManagerClient_removeRights(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
+    LOGV("removeRights");
+    return getDrmManagerClientImpl(env, thiz)
+               ->removeRights(uniqueId, Utility::getStringValue(env, path));
+}
+
+static jint android_drm_DrmManagerClient_removeAllRights(
+            JNIEnv* env, jobject thiz, jint uniqueId) {
+    LOGV("removeAllRights");
+    return getDrmManagerClientImpl(env, thiz)->removeAllRights(uniqueId);
+}
+
+static jint android_drm_DrmManagerClient_openConvertSession(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring mimeType) {
+    LOGV("openConvertSession Enter");
+    int convertId
+        = getDrmManagerClientImpl(env, thiz)
+            ->openConvertSession(uniqueId, Utility::getStringValue(env, mimeType));
+    LOGV("openConvertSession Exit");
+    return convertId;
+}
+
+static jobject android_drm_DrmManagerClient_convertData(
+            JNIEnv* env, jobject thiz, jint uniqueId, jint convertId, jbyteArray inputData) {
+    LOGV("convertData Enter");
+
+    int dataLength = 0;
+    char* mData = Utility::getByteArrayValue(env, inputData, &dataLength);
+    const DrmBuffer buffer(mData, dataLength);
+
+    DrmConvertedStatus* pDrmConvertedStatus
+            = getDrmManagerClientImpl(env, thiz)->convertData(uniqueId, convertId, &buffer);
+
+    jclass localRef = env->FindClass("android/drm/DrmConvertedStatus");
+
+    jobject drmConvertedStatus = NULL;
+
+    if (NULL != localRef && NULL != pDrmConvertedStatus) {
+        int statusCode = pDrmConvertedStatus->statusCode;
+
+        jbyteArray dataArray = NULL;
+        if (NULL != pDrmConvertedStatus->convertedData) {
+            int length = pDrmConvertedStatus->convertedData->length;
+            dataArray = env->NewByteArray(length);
+            env->SetByteArrayRegion(dataArray, 0, length,
+                            (jbyte*) pDrmConvertedStatus->convertedData->data);
+
+            delete [] pDrmConvertedStatus->convertedData->data;
+            delete pDrmConvertedStatus->convertedData; pDrmConvertedStatus->convertedData = NULL;
+        }
+        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "(I[BI)V");
+        drmConvertedStatus
+            = env->NewObject(localRef, constructorId,
+                             statusCode, dataArray, pDrmConvertedStatus->offset);
+    }
+
+    delete mData; mData = NULL;
+    delete pDrmConvertedStatus; pDrmConvertedStatus = NULL;
+
+    LOGV("convertData - Exit");
+    return drmConvertedStatus;
+}
+
+static jobject android_drm_DrmManagerClient_closeConvertSession(
+            JNIEnv* env, jobject thiz, int uniqueId, jint convertId) {
+
+    LOGV("closeConvertSession Enter");
+
+    DrmConvertedStatus* pDrmConvertedStatus
+                = getDrmManagerClientImpl(env, thiz)->closeConvertSession(uniqueId, convertId);
+
+    jclass localRef = env->FindClass("android/drm/DrmConvertedStatus");
+
+    jobject drmConvertedStatus = NULL;
+
+    if (NULL != localRef && NULL != pDrmConvertedStatus) {
+        int statusCode = pDrmConvertedStatus->statusCode;
+
+        jbyteArray dataArray = NULL;
+        if (NULL != pDrmConvertedStatus->convertedData) {
+            int length = pDrmConvertedStatus->convertedData->length;
+            dataArray = env->NewByteArray(length);
+            env->SetByteArrayRegion(
+                dataArray, 0, length, (jbyte*) pDrmConvertedStatus->convertedData->data);
+
+            delete [] pDrmConvertedStatus->convertedData->data;
+            delete pDrmConvertedStatus->convertedData; pDrmConvertedStatus->convertedData = NULL;
+        }
+        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "(I[BI)V");
+        drmConvertedStatus
+            = env->NewObject(localRef, constructorId,
+                             statusCode, dataArray, pDrmConvertedStatus->offset);
+    }
+
+    delete pDrmConvertedStatus; pDrmConvertedStatus = NULL;
+
+    LOGV("closeConvertSession - Exit");
+    return drmConvertedStatus;
+}
+
+static JNINativeMethod nativeMethods[] = {
+
+    {"_loadPlugIns", "(ILjava/lang/Object;)I",
+                                    (void*)android_drm_DrmManagerClient_loadPlugIns},
+
+    {"_unloadPlugIns", "(I)I",
+                                    (void*)android_drm_DrmManagerClient_unloadPlugIns},
+
+    {"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
+                                    (void*)android_drm_DrmManagerClient_getConstraintsFromContent},
+
+    {"_getAllSupportInfo", "(I)[Landroid/drm/DrmSupportInfo;",
+                                    (void*)android_drm_DrmManagerClient_getAllSupportInfo},
+
+    {"_installDrmEngine", "(ILjava/lang/String;)V",
+                                    (void*)android_drm_DrmManagerClient_installDrmEngine},
+
+    {"_canHandle", "(ILjava/lang/String;Ljava/lang/String;)Z",
+                                    (void*)android_drm_DrmManagerClient_canHandle},
+
+    {"_processDrmInfo", "(ILandroid/drm/DrmInfo;)Landroid/drm/DrmInfoStatus;",
+                                    (void*)android_drm_DrmManagerClient_processDrmInfo},
+
+    {"_acquireDrmInfo", "(ILandroid/drm/DrmInfoRequest;)Landroid/drm/DrmInfo;",
+                                    (void*)android_drm_DrmManagerClient_acquireDrmInfo},
+
+    {"_saveRights", "(ILandroid/drm/DrmRights;Ljava/lang/String;Ljava/lang/String;)I",
+                                    (void*)android_drm_DrmManagerClient_saveRights},
+
+    {"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
+                                    (void*)android_drm_DrmManagerClient_getDrmObjectType},
+
+    {"_getOriginalMimeType", "(ILjava/lang/String;)Ljava/lang/String;",
+                                    (void*)android_drm_DrmManagerClient_getOriginalMimeType},
+
+    {"_checkRightsStatus", "(ILjava/lang/String;I)I",
+                                    (void*)android_drm_DrmManagerClient_checkRightsStatus},
+
+    {"_removeRights", "(ILjava/lang/String;)I",
+                                    (void*)android_drm_DrmManagerClient_removeRights},
+
+    {"_removeAllRights", "(I)I",
+                                    (void*)android_drm_DrmManagerClient_removeAllRights},
+
+    {"_openConvertSession", "(ILjava/lang/String;)I",
+                                    (void*)android_drm_DrmManagerClient_openConvertSession},
+
+    {"_convertData", "(II[B)Landroid/drm/DrmConvertedStatus;",
+                                    (void*)android_drm_DrmManagerClient_convertData},
+
+    {"_closeConvertSession", "(II)Landroid/drm/DrmConvertedStatus;",
+                                    (void*)android_drm_DrmManagerClient_closeConvertSession},
+};
+
+static int registerNativeMethods(JNIEnv* env) {
+    int result = -1;
+
+    /* look up the class */
+    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
+
+    if (NULL != clazz) {
+        if (env->RegisterNatives(clazz, nativeMethods, sizeof(nativeMethods)
+                / sizeof(nativeMethods[0])) == JNI_OK) {
+            result = 0;
+        }
+    }
+    return result;
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
+        if (NULL != env && registerNativeMethods(env) == 0) {
+            result = JNI_VERSION_1_4;
+        }
+    }
+    return result;
+}
+
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
new file mode 100644
index 0000000..99133ba
--- /dev/null
+++ b/drm/libdrmframework/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    DrmManagerClientImpl.cpp \
+    DrmManagerClient.cpp
+
+LOCAL_MODULE:= libdrmframework
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    libbinder
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+    libdrmframeworkcommon
+
+LOCAL_C_INCLUDES += \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/include
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
new file mode 100644
index 0000000..c996994
--- /dev/null
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+#include <binder/IServiceManager.h>
+#include <drm/DrmManagerClient.h>
+
+#include "DrmManagerClientImpl.h"
+
+using namespace android;
+
+DrmManagerClient::DrmManagerClient() {
+    int uniqueId = 0;
+    mDrmManagerClientImpl = NULL;
+
+    mDrmManagerClientImpl = DrmManagerClientImpl::create(&uniqueId);
+    mUniqueId = uniqueId;
+
+    loadPlugIns();
+}
+
+DrmManagerClient::~DrmManagerClient() {
+    DrmManagerClientImpl::remove(mUniqueId);
+    unloadPlugIns();
+
+    delete mDrmManagerClientImpl; mDrmManagerClientImpl = NULL;
+}
+
+status_t DrmManagerClient::loadPlugIns() {
+    return mDrmManagerClientImpl->loadPlugIns(mUniqueId);
+}
+
+status_t DrmManagerClient::setOnInfoListener(
+                    const sp<DrmManagerClient::OnInfoListener>& infoListener) {
+    return mDrmManagerClientImpl->setOnInfoListener(mUniqueId, infoListener);
+}
+
+status_t DrmManagerClient::unloadPlugIns() {
+    return mDrmManagerClientImpl->unloadPlugIns(mUniqueId);
+}
+
+DrmConstraints* DrmManagerClient::getConstraints(const String8* path, const int action) {
+    return mDrmManagerClientImpl->getConstraints(mUniqueId, path, action);
+}
+
+bool DrmManagerClient::canHandle(const String8& path, const String8& mimeType) {
+    return mDrmManagerClientImpl->canHandle(mUniqueId, path, mimeType);
+}
+
+DrmInfoStatus* DrmManagerClient::processDrmInfo(const DrmInfo* drmInfo) {
+    return mDrmManagerClientImpl->processDrmInfo(mUniqueId, drmInfo);
+}
+
+DrmInfo* DrmManagerClient::acquireDrmInfo(const DrmInfoRequest* drmInfoRequest) {
+    return mDrmManagerClientImpl->acquireDrmInfo(mUniqueId, drmInfoRequest);
+}
+
+status_t DrmManagerClient::saveRights(
+        const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath) {
+    return mDrmManagerClientImpl->saveRights(mUniqueId, drmRights, rightsPath, contentPath);
+}
+
+String8 DrmManagerClient::getOriginalMimeType(const String8& path) {
+    return mDrmManagerClientImpl->getOriginalMimeType(mUniqueId, path);
+}
+
+int DrmManagerClient::getDrmObjectType(const String8& path, const String8& mimeType) {
+    return mDrmManagerClientImpl->getDrmObjectType( mUniqueId, path, mimeType);
+}
+
+int DrmManagerClient::checkRightsStatus(const String8& path, int action) {
+    return mDrmManagerClientImpl->checkRightsStatus(mUniqueId, path, action);
+}
+
+status_t DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) {
+    return mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve);
+}
+
+status_t DrmManagerClient::setPlaybackStatus(
+            DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    return mDrmManagerClientImpl
+            ->setPlaybackStatus(mUniqueId, decryptHandle, playbackStatus, position);
+}
+
+bool DrmManagerClient::validateAction(
+            const String8& path, int action, const ActionDescription& description) {
+    return mDrmManagerClientImpl->validateAction(mUniqueId, path, action, description);
+}
+
+status_t DrmManagerClient::removeRights(const String8& path) {
+    return mDrmManagerClientImpl->removeRights(mUniqueId, path);
+}
+
+status_t DrmManagerClient::removeAllRights() {
+    return mDrmManagerClientImpl->removeAllRights(mUniqueId);
+}
+
+int DrmManagerClient::openConvertSession(const String8& mimeType) {
+    return mDrmManagerClientImpl->openConvertSession(mUniqueId, mimeType);
+}
+
+DrmConvertedStatus* DrmManagerClient::convertData(int convertId, const DrmBuffer* inputData) {
+    return mDrmManagerClientImpl->convertData(mUniqueId, convertId, inputData);
+}
+
+DrmConvertedStatus* DrmManagerClient::closeConvertSession(int convertId) {
+    return mDrmManagerClientImpl->closeConvertSession(mUniqueId, convertId);
+}
+
+status_t DrmManagerClient::getAllSupportInfo(int* length, DrmSupportInfo** drmSupportInfoArray) {
+    return mDrmManagerClientImpl->getAllSupportInfo(mUniqueId, length, drmSupportInfoArray);
+}
+
+DecryptHandle* DrmManagerClient::openDecryptSession(int fd, int offset, int length) {
+    return mDrmManagerClientImpl->openDecryptSession(mUniqueId, fd, offset, length);
+}
+
+status_t DrmManagerClient::closeDecryptSession(DecryptHandle* decryptHandle) {
+    return mDrmManagerClientImpl->closeDecryptSession(mUniqueId, decryptHandle);
+}
+
+status_t DrmManagerClient::initializeDecryptUnit(
+            DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    return mDrmManagerClientImpl->initializeDecryptUnit(
+            mUniqueId, decryptHandle, decryptUnitId, headerInfo);
+}
+
+status_t DrmManagerClient::decrypt(
+    DecryptHandle* decryptHandle, int decryptUnitId,
+    const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    return mDrmManagerClientImpl->decrypt(
+            mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+}
+
+status_t DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) {
+    return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, decryptHandle, decryptUnitId);
+}
+
+ssize_t DrmManagerClient::pread(
+            DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off_t offset) {
+    return mDrmManagerClientImpl->pread(mUniqueId, decryptHandle, buffer, numBytes, offset);
+}
+
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
new file mode 100644
index 0000000..272adcd
--- /dev/null
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmManagerClientImpl(Native)"
+#include <utils/Log.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <binder/IServiceManager.h>
+
+#include "DrmManagerClientImpl.h"
+
+using namespace android;
+
+#define INVALID_VALUE -1
+
+Mutex DrmManagerClientImpl::mMutex;
+sp<IDrmManagerService> DrmManagerClientImpl::mDrmManagerService;
+const String8 DrmManagerClientImpl::EMPTY_STRING("");
+
+DrmManagerClientImpl* DrmManagerClientImpl::create(int* pUniqueId) {
+    if (0 == *pUniqueId) {
+        int uniqueId = getDrmManagerService()->addUniqueId(*pUniqueId);
+        *pUniqueId = uniqueId;
+    } else {
+        getDrmManagerService()->addUniqueId(*pUniqueId);
+    }
+    return new DrmManagerClientImpl();
+}
+
+void DrmManagerClientImpl::remove(int uniqueId) {
+    getDrmManagerService()->removeUniqueId(uniqueId);
+}
+
+DrmManagerClientImpl::DrmManagerClientImpl() {
+
+}
+
+DrmManagerClientImpl::~DrmManagerClientImpl() {
+
+}
+
+const sp<IDrmManagerService>& DrmManagerClientImpl::getDrmManagerService() {
+    mMutex.lock();
+    if (NULL == mDrmManagerService.get()) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("drm.drmManager"));
+            if (binder != 0) {
+                break;
+            }
+            LOGW("DrmManagerService not published, waiting...");
+            struct timespec reqt;
+            reqt.tv_sec  = 0;
+            reqt.tv_nsec = 500000000; //0.5 sec
+            nanosleep(&reqt, NULL);
+        } while (true);
+
+        mDrmManagerService = interface_cast<IDrmManagerService>(binder);
+    }
+    mMutex.unlock();
+    return mDrmManagerService;
+}
+
+status_t DrmManagerClientImpl::loadPlugIns(int uniqueId) {
+    return getDrmManagerService()->loadPlugIns(uniqueId);
+}
+
+status_t DrmManagerClientImpl::loadPlugIns(int uniqueId, const String8& plugInDirPath) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (EMPTY_STRING != plugInDirPath) {
+        status = getDrmManagerService()->loadPlugIns(uniqueId, plugInDirPath);
+    }
+    return status;
+}
+
+status_t DrmManagerClientImpl::setOnInfoListener(
+            int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener) {
+    Mutex::Autolock _l(mLock);
+    mOnInfoListener = infoListener;
+    return getDrmManagerService()->setDrmServiceListener(uniqueId, this);
+}
+
+status_t DrmManagerClientImpl::unloadPlugIns(int uniqueId) {
+    return getDrmManagerService()->unloadPlugIns(uniqueId);
+}
+
+status_t DrmManagerClientImpl::installDrmEngine(int uniqueId, const String8& drmEngineFile) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (EMPTY_STRING != drmEngineFile) {
+        status = getDrmManagerService()->installDrmEngine(uniqueId, drmEngineFile);
+    }
+    return status;
+}
+
+DrmConstraints* DrmManagerClientImpl::getConstraints(
+        int uniqueId, const String8* path, const int action) {
+    DrmConstraints *drmConstraints = NULL;
+    if ((NULL != path) && (EMPTY_STRING != *path)) {
+        drmConstraints = getDrmManagerService()->getConstraints(uniqueId, path, action);
+    }
+    return drmConstraints;
+}
+
+bool DrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+    bool retCode = false;
+    if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) {
+        retCode = getDrmManagerService()->canHandle(uniqueId, path, mimeType);
+    }
+    return retCode;
+}
+
+DrmInfoStatus* DrmManagerClientImpl::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    DrmInfoStatus *drmInfoStatus = NULL;
+    if (NULL != drmInfo) {
+        drmInfoStatus = getDrmManagerService()->processDrmInfo(uniqueId, drmInfo);
+    }
+    return drmInfoStatus;
+}
+
+DrmInfo* DrmManagerClientImpl::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    DrmInfo* drmInfo = NULL;
+    if (NULL != drmInfoRequest) {
+        drmInfo = getDrmManagerService()->acquireDrmInfo(uniqueId, drmInfoRequest);
+    }
+    return drmInfo;
+}
+
+status_t DrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (EMPTY_STRING != contentPath) {
+        status = getDrmManagerService()->saveRights(uniqueId, drmRights, rightsPath, contentPath);
+    }
+    return status;
+}
+
+String8 DrmManagerClientImpl::getOriginalMimeType(int uniqueId, const String8& path) {
+    String8 mimeType = EMPTY_STRING;
+    if (EMPTY_STRING != path) {
+        mimeType = getDrmManagerService()->getOriginalMimeType(uniqueId, path);
+    }
+    return mimeType;
+}
+
+int DrmManagerClientImpl::getDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) {
+    int drmOjectType = DrmObjectType::UNKNOWN;
+    if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) {
+         drmOjectType = getDrmManagerService()->getDrmObjectType(uniqueId, path, mimeType);
+    }
+    return drmOjectType;
+}
+
+int DrmManagerClientImpl::checkRightsStatus(
+            int uniqueId, const String8& path, int action) {
+    int rightsStatus = RightsStatus::RIGHTS_INVALID;
+    if (EMPTY_STRING != path) {
+        rightsStatus = getDrmManagerService()->checkRightsStatus(uniqueId, path, action);
+    }
+    return rightsStatus;
+}
+
+status_t DrmManagerClientImpl::consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (NULL != decryptHandle) {
+        status = getDrmManagerService()->consumeRights(uniqueId, decryptHandle, action, reserve);
+    }
+    return status;
+}
+
+status_t DrmManagerClientImpl::setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (NULL != decryptHandle) {
+        status = getDrmManagerService()->setPlaybackStatus(
+                uniqueId, decryptHandle, playbackStatus, position);
+    }
+    return status;
+}
+
+bool DrmManagerClientImpl::validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description) {
+    bool retCode = false;
+    if (EMPTY_STRING != path) {
+        retCode = getDrmManagerService()->validateAction(uniqueId, path, action, description);
+    }
+    return retCode;
+}
+
+status_t DrmManagerClientImpl::removeRights(int uniqueId, const String8& path) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (EMPTY_STRING != path) {
+        status = getDrmManagerService()->removeRights(uniqueId, path);
+    }
+    return status;
+}
+
+status_t DrmManagerClientImpl::removeAllRights(int uniqueId) {
+    return getDrmManagerService()->removeAllRights(uniqueId);
+}
+
+int DrmManagerClientImpl::openConvertSession(int uniqueId, const String8& mimeType) {
+    int retCode = INVALID_VALUE;
+    if (EMPTY_STRING != mimeType) {
+        retCode = getDrmManagerService()->openConvertSession(uniqueId, mimeType);
+    }
+    return retCode;
+}
+
+DrmConvertedStatus* DrmManagerClientImpl::convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) {
+    DrmConvertedStatus* drmConvertedStatus = NULL;
+    if (NULL != inputData) {
+         drmConvertedStatus = getDrmManagerService()->convertData(uniqueId, convertId, inputData);
+    }
+    return drmConvertedStatus;
+}
+
+DrmConvertedStatus* DrmManagerClientImpl::closeConvertSession(int uniqueId, int convertId) {
+    return getDrmManagerService()->closeConvertSession(uniqueId, convertId);
+}
+
+status_t DrmManagerClientImpl::getAllSupportInfo(
+            int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if ((NULL != drmSupportInfoArray) && (NULL != length)) {
+        status = getDrmManagerService()->getAllSupportInfo(uniqueId, length, drmSupportInfoArray);
+    }
+    return status;
+}
+
+DecryptHandle* DrmManagerClientImpl::openDecryptSession(
+            int uniqueId, int fd, int offset, int length) {
+    return getDrmManagerService()->openDecryptSession(uniqueId, fd, offset, length);
+}
+
+status_t DrmManagerClientImpl::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (NULL != decryptHandle) {
+        status = getDrmManagerService()->closeDecryptSession( uniqueId, decryptHandle);
+    }
+    return status;
+}
+
+status_t DrmManagerClientImpl::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if ((NULL != decryptHandle) && (NULL != headerInfo)) {
+        status = getDrmManagerService()->initializeDecryptUnit(
+                uniqueId, decryptHandle, decryptUnitId, headerInfo);
+    }
+    return status;
+}
+
+status_t DrmManagerClientImpl::decrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if ((NULL != decryptHandle) && (NULL != encBuffer)
+        && (NULL != decBuffer) && (NULL != *decBuffer)) {
+        status = getDrmManagerService()->decrypt(
+                uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+    }
+    return status;
+}
+
+status_t DrmManagerClientImpl::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (NULL != decryptHandle) {
+        status
+            = getDrmManagerService()->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+    }
+    return status;
+}
+
+ssize_t DrmManagerClientImpl::pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset) {
+    ssize_t retCode = INVALID_VALUE;
+    if ((NULL != decryptHandle) && (NULL != buffer) && (0 < numBytes)) {
+        retCode = getDrmManagerService()->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
+    }
+    return retCode;
+}
+
+status_t DrmManagerClientImpl::notify(const DrmInfoEvent& event) {
+    if (NULL != mOnInfoListener.get()) {
+        Mutex::Autolock _l(mLock);
+        sp<DrmManagerClient::OnInfoListener> listener = mOnInfoListener;
+        listener->onInfo(event);
+    }
+    return DRM_NO_ERROR;
+}
+
diff --git a/drm/libdrmframework/include/DrmIOService.h b/drm/libdrmframework/include/DrmIOService.h
new file mode 100644
index 0000000..244124e
--- /dev/null
+++ b/drm/libdrmframework/include/DrmIOService.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_IO_SERVICE_H__
+#define __DRM_IO_SERVICE_H__
+
+#include "IDrmIOService.h"
+
+namespace android {
+
+/**
+ * This is the implementation class for DRM IO service.
+ *
+ * The instance of this class is created while starting the DRM IO service.
+ *
+ */
+class DrmIOService : public BnDrmIOService {
+public:
+    static void instantiate();
+
+private:
+    DrmIOService();
+    virtual ~DrmIOService();
+
+public:
+    void writeToFile(const String8& filePath, const String8& dataBuffer);
+    String8 readFromFile(const String8& filePath);
+};
+
+};
+
+#endif /* __DRM_IO_SERVICE_H__ */
+
diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/libdrmframework/include/DrmManager.h
new file mode 100644
index 0000000..dc3e460
--- /dev/null
+++ b/drm/libdrmframework/include/DrmManager.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_MANAGER_H__
+#define __DRM_MANAGER_H__
+
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <drm/drm_framework_common.h>
+#include "IDrmEngine.h"
+#include "PlugInManager.h"
+#include "IDrmServiceListener.h"
+
+namespace android {
+
+class IDrmManager;
+class DrmRegistrationInfo;
+class DrmUnregistrationInfo;
+class DrmRightsAcquisitionInfo;
+class DrmContentIds;
+class DrmConstraints;
+class DrmRights;
+class DrmInfo;
+class DrmInfoStatus;
+class DrmConvertedStatus;
+class DrmInfoRequest;
+class DrmSupportInfo;
+class ActionDescription;
+
+/**
+ * This is implementation class for DRM Manager. This class delegates the
+ * functionality to corresponding DRM Engine.
+ *
+ * The DrmManagerService class creates an instance of this class.
+ *
+ */
+class DrmManager : public IDrmEngine::OnInfoListener {
+public:
+    DrmManager();
+    virtual ~DrmManager();
+
+public:
+    int addUniqueId(int uniqueId);
+
+    void removeUniqueId(int uniqueId);
+
+    status_t loadPlugIns(int uniqueId);
+
+    status_t loadPlugIns(int uniqueId, const String8& plugInDirPath);
+
+    status_t setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& drmServiceListener);
+
+    status_t unloadPlugIns(int uniqueId);
+
+    status_t installDrmEngine(int uniqueId, const String8& drmEngineFile);
+
+    DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
+
+    bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
+
+    DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
+
+    status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    String8 getOriginalMimeType(int uniqueId, const String8& path);
+
+    int getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    int checkRightsStatus(int uniqueId, const String8& path, int action);
+
+    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    status_t setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    status_t removeRights(int uniqueId, const String8& path);
+
+    status_t removeAllRights(int uniqueId);
+
+    int openConvertSession(int uniqueId, const String8& mimeType);
+
+    DrmConvertedStatus* convertData(int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    DrmConvertedStatus* closeConvertSession(int uniqueId, int convertId);
+
+    status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
+
+    DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
+
+    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset);
+
+    void onInfo(const DrmInfoEvent& event);
+
+private:
+    String8 getSupportedPlugInId(int uniqueId, const String8& path, const String8& mimeType);
+
+    String8 getSupportedPlugInId(const String8& mimeType);
+
+    String8 getSupportedPlugInIdFromPath(int uniqueId, const String8& path);
+
+    void populate(int uniqueId);
+
+    bool canHandle(int uniqueId, const String8& path);
+
+    void initializePlugIns(int uniqueId);
+
+private:
+    static Vector<int> mUniqueIdVector;
+    static const String8 EMPTY_STRING;
+
+    int mDecryptSessionId;
+    int mConvertId;
+    Mutex mLock;
+    Mutex mDecryptLock;
+    Mutex mConvertLock;
+    TPlugInManager<IDrmEngine> mPlugInManager;
+    KeyedVector< DrmSupportInfo, String8 > mSupportInfoToPlugInIdMap;
+    KeyedVector< int, IDrmEngine*> mConvertSessionMap;
+    KeyedVector< int, sp<IDrmServiceListener> > mServiceListeners;
+    KeyedVector< int, IDrmEngine*> mDecryptSessionMap;
+};
+
+};
+
+#endif /* __DRM_MANAGER_H__ */
+
diff --git a/drm/libdrmframework/include/DrmManagerClientImpl.h b/drm/libdrmframework/include/DrmManagerClientImpl.h
new file mode 100644
index 0000000..492c7f5
--- /dev/null
+++ b/drm/libdrmframework/include/DrmManagerClientImpl.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_MANAGER_CLIENT_IMPL_H__
+#define __DRM_MANAGER_CLIENT_IMPL_H__
+
+#include <binder/IMemory.h>
+#include <utils/threads.h>
+#include <drm/DrmManagerClient.h>
+
+#include "IDrmManagerService.h"
+
+namespace android {
+
+class DrmInfoEvent;
+/**
+ * This is implementation class for DrmManagerClient class.
+ *
+ * Only the JNI layer creates an instance of this class to delegate
+ * functionality to Native later.
+ *
+ */
+class DrmManagerClientImpl : public BnDrmServiceListener {
+private:
+    DrmManagerClientImpl();
+
+public:
+    static DrmManagerClientImpl* create(int* pUniqueId);
+
+    static void remove(int uniqueId);
+
+    virtual ~DrmManagerClientImpl();
+
+public:
+    /**
+     * Initialize DRM Manager
+     *     load available plug-ins from default plugInDirPath
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t loadPlugIns(int uniqueId);
+
+    /**
+     * Finalize DRM Manager
+     *     release resources associated with each plug-in
+     *     unload all plug-ins and etc.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t unloadPlugIns(int uniqueId);
+
+    /**
+     * Register a callback to be invoked when the caller required to
+     * receive necessary information
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] infoListener Listener
+     * @return status_t
+     *            Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t setOnInfoListener(
+            int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener);
+
+    /**
+     * Get constraint information associated with input content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Actions defined such as,
+     *     Action::DEFAULT, Action::PLAY, etc
+     * @return DrmConstraints
+     *     key-value pairs of constraint are embedded in it
+     * @note
+     *     In case of error, return NULL
+     */
+    DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
+
+    /**
+     * Check whether the given mimetype or path can be handled
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the content needs to be handled
+     * @param[in] mimetype Mimetype of the content needs to be handled
+     * @return
+     *     True if DrmManager can handle given path or mime type.
+     */
+    bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
+
+    /**
+     * Executes given drm information based on its type
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmInfo Information needs to be processed
+     * @return DrmInfoStatus
+     *     instance as a result of processing given input
+     */
+    DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    /**
+     * Retrieves necessary information for registration, unregistration or rights
+     * acquisition information.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmInfoRequest Request information to retrieve drmInfo
+     * @return DrmInfo
+     *     instance as a result of processing given input
+     */
+    DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
+
+    /**
+     * Save DRM rights to specified rights path
+     * and make association with content path
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmRights DrmRights to be saved
+     * @param[in] rightsPath File path where rights to be saved
+     * @param[in] contentPath File path where content was saved
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    /**
+     * Retrieves the mime type embedded inside the original content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path the path of the protected content
+     * @return String8
+     *     Returns mime-type of the original content, such as "video/mpeg"
+     */
+    String8 getOriginalMimeType(int uniqueId, const String8& path);
+
+    /**
+     * Retrieves the type of the protected object (content, rights, etc..)
+     * using specified path or mimetype. At least one parameter should be non null
+     * to retrieve DRM object type
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the content or null.
+     * @param[in] mimeType Mime type of the content or null.
+     * @return type of the DRM content,
+     *     such as DrmObjectType::CONTENT, DrmObjectType::RIGHTS_OBJECT
+     */
+    int getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    /**
+     * Check whether the given content has valid rights or not
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to perform (Action::DEFAULT, Action::PLAY, etc)
+     * @return the status of the rights for the protected content,
+     *     such as RightsStatus::RIGHTS_VALID, RightsStatus::RIGHTS_EXPIRED, etc.
+     */
+    int checkRightsStatus(int uniqueId, const String8& path, int action);
+
+    /**
+     * Consumes the rights for a content.
+     * If the reserve parameter is true the rights is reserved until the same
+     * application calls this api again with the reserve parameter set to false.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
+     * @param[in] reserve True if the rights should be reserved.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    /**
+     * Informs the DRM engine about the playback actions performed on the DRM files.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
+     * @param[in] position Position in the file (in milliseconds) where the start occurs.
+     *     Only valid together with Playback::START.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    /**
+     * Validates whether an action on the DRM content is allowed or not.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to validate (Action::PLAY, Action::TRANSFER, etc)
+     * @param[in] description Detailed description of the action
+     * @return true if the action is allowed.
+     */
+    bool validateAction(
+        int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t removeRights(int uniqueId, const String8& path);
+
+    /**
+     * Removes all the rights information of each plug-in associated with
+     * DRM framework. Will be used in master reset
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t removeAllRights(int uniqueId);
+
+    /**
+     * This API is for Forward Lock based DRM scheme.
+     * Each time the application tries to download a new DRM file
+     * which needs to be converted, then the application has to
+     * begin with calling this API.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] mimeType Description/MIME type of the input data packet
+     * @return Return handle for the convert session
+     */
+    int openConvertSession(int uniqueId, const String8& mimeType);
+
+    /**
+     * Accepts and converts the input data which is part of DRM file.
+     * The resultant converted data and the status is returned in the DrmConvertedInfo
+     * object. This method will be called each time there are new block
+     * of data received by the application.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @param[in] inputData Input Data which need to be converted
+     * @return Return object contains the status of the data conversion,
+     *     the output converted data and offset. In this case the
+     *     application will ignore the offset information.
+     */
+    DrmConvertedStatus* convertData(int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    /**
+     * Informs the Drm Agent when there is no more data which need to be converted
+     * or when an error occurs. Upon successful conversion of the complete data,
+     * the agent will inform that where the header and body signature
+     * should be added. This signature appending is needed to integrity
+     * protect the converted file.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @return Return object contains the status of the data conversion,
+     *     the header and body signature data. It also informs
+     *     the application on which offset these signature data
+     *     should be appended.
+     */
+    DrmConvertedStatus* closeConvertSession(int uniqueId, int convertId);
+
+    /**
+     * Retrieves all DrmSupportInfo instance that native DRM framework can handle.
+     * This interface is meant to be used by JNI layer
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[out] length Number of elements in drmSupportInfoArray
+     * @param[out] drmSupportInfoArray Array contains all DrmSupportInfo
+     *             that native DRM framework can handle
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
+
+    /**
+     * Open the decrypt session to decrypt the given protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] fd File descriptor of the protected content to be decrypted
+     * @param[in] offset Start position of the content
+     * @param[in] length The length of the protected content
+     * @return
+     *     Handle for the decryption session
+     */
+    DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
+
+    /**
+     * Close the decrypt session for the given handle
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    /**
+     * Initialize decryption for the given unit of the protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @param[in] headerInfo Information for initializing decryption of this decrypUnit
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    /**
+     * Decrypt the protected content buffers for the given unit
+     * This method will be called any number of times, based on number of
+     * encrypted streams received from application.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @param[in] encBuffer Encrypted data block
+     * @param[out] decBuffer Decrypted data block
+     * @param[in] IV Optional buffer
+     * @return status_t
+     *     Returns the error code for this API
+     *     DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
+     *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
+     *     DRM_ERROR_DECRYPT for failure.
+     */
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    /**
+     * Finalize decryption for the given unit of the protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    /**
+     * Reads the specified number of bytes from an open DRM file.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[out] buffer Reference to the buffer that should receive the read data.
+     * @param[in] numBytes Number of bytes to read.
+     * @param[in] offset Offset with which to update the file position.
+     *
+     * @return Number of bytes read. Returns -1 for Failure.
+     */
+    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset);
+
+    /**
+     * Notify the event to the registered listener
+     *
+     * @param[in] event The event to be notified
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t notify(const DrmInfoEvent& event);
+
+private:
+    /**
+     * Initialize DRM Manager
+     *     load available plug-ins from plugInDirPath
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] plugInDirPath Directory from where to load plug-ins
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t loadPlugIns(int uniqueId, const String8& plugInDirPath);
+
+    /**
+     * Install new DRM Engine Plug-in at the runtime
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmEngine Shared Object(so) File in which DRM Engine defined
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t installDrmEngine(int uniqueId, const String8& drmEngineFile);
+
+private:
+    Mutex mLock;
+    sp<DrmManagerClient::OnInfoListener> mOnInfoListener;
+
+private:
+    static Mutex mMutex;
+    static sp<IDrmManagerService> mDrmManagerService;
+    static const sp<IDrmManagerService>& getDrmManagerService();
+    static const String8 EMPTY_STRING;
+};
+
+};
+
+#endif /* __DRM_MANAGER_CLIENT_IMPL_H__ */
+
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h
new file mode 100644
index 0000000..f455e15
--- /dev/null
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_MANAGER_SERVICE_H__
+#define __DRM_MANAGER_SERVICE_H__
+
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include "IDrmManagerService.h"
+#include "IDrmServiceListener.h"
+
+namespace android {
+
+class DrmManager;
+class String8;
+class Mutex;
+
+/**
+ * This is the implementation class for DRM manager service. This delegates
+ * the responsibility to DrmManager.
+ *
+ * The instance of this class is created while starting the DRM manager service.
+ *
+ */
+class DrmManagerService : public BnDrmManagerService {
+public:
+    static void instantiate();
+
+private:
+    DrmManagerService();
+    virtual ~DrmManagerService();
+
+public:
+    int addUniqueId(int uniqueId);
+
+    void removeUniqueId(int uniqueId);
+
+    status_t loadPlugIns(int uniqueId);
+
+    status_t loadPlugIns(int uniqueId, const String8& plugInDirPath);
+
+    status_t setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& drmServiceListener);
+
+    status_t unloadPlugIns(int uniqueId);
+
+    status_t installDrmEngine(int uniqueId, const String8& drmEngineFile);
+
+    DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
+
+    bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
+
+    DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest);
+
+    status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    String8 getOriginalMimeType(int uniqueId, const String8& path);
+
+    int getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    int checkRightsStatus(int uniqueId, const String8& path,int action);
+
+    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    status_t setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool validateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description);
+
+    status_t removeRights(int uniqueId, const String8& path);
+
+    status_t removeAllRights(int uniqueId);
+
+    int openConvertSession(int uniqueId, const String8& mimeType);
+
+    DrmConvertedStatus* convertData(int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    DrmConvertedStatus* closeConvertSession(int uniqueId, int convertId);
+
+    status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
+
+    DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
+
+    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset);
+
+private:
+    DrmManager* mDrmManager;
+};
+
+};
+
+#endif /* __DRM_MANAGER_SERVICE_H__ */
+
diff --git a/drm/libdrmframework/include/IDrmIOService.h b/drm/libdrmframework/include/IDrmIOService.h
new file mode 100644
index 0000000..5e0d907
--- /dev/null
+++ b/drm/libdrmframework/include/IDrmIOService.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IDRM_IO_SERVICE_H__
+#define __IDRM_IO_SERVICE_H__
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/**
+ * This is the interface class for DRM IO service.
+ *
+ */
+class IDrmIOService : public IInterface
+{
+public:
+    enum {
+        WRITE_TO_FILE = IBinder::FIRST_CALL_TRANSACTION,
+        READ_FROM_FILE
+    };
+
+public:
+    DECLARE_META_INTERFACE(DrmIOService);
+
+public:
+    /**
+     * Writes the data into the file path provided
+     *
+     * @param[in] filePath Path of the file
+     * @param[in] dataBuffer Data to write
+     */
+    virtual void writeToFile(const String8& filePath, const String8& dataBuffer) = 0;
+
+    /**
+     * Reads the data from the file path provided
+     *
+     * @param[in] filePath Path of the file
+     * @return Data read from the file
+     */
+    virtual String8 readFromFile(const String8& filePath) = 0;
+};
+
+/**
+ * This is the Binder implementation class for DRM IO service.
+ */
+class BpDrmIOService: public BpInterface<IDrmIOService>
+{
+public:
+    BpDrmIOService(const sp<IBinder>& impl)
+            : BpInterface<IDrmIOService>(impl) {}
+
+    virtual void writeToFile(const String8& filePath, const String8& dataBuffer);
+
+    virtual String8 readFromFile(const String8& filePath);
+};
+
+/**
+ * This is the Binder implementation class for DRM IO service.
+ */
+class BnDrmIOService: public BnInterface<IDrmIOService>
+{
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+};
+
+#endif /* __IDRM_IO_SERVICE_H__ */
+
diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/libdrmframework/include/IDrmManagerService.h
new file mode 100644
index 0000000..5c668ed
--- /dev/null
+++ b/drm/libdrmframework/include/IDrmManagerService.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IDRM_MANAGER_SERVICE_H__
+#define __IDRM_MANAGER_SERVICE_H__
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <drm/drm_framework_common.h>
+#include "IDrmServiceListener.h"
+
+namespace android {
+
+class DrmContentIds;
+class DrmConstraints;
+class DrmRights;
+class DrmInfo;
+class DrmInfoStatus;
+class DrmInfoRequest;
+class DrmSupportInfo;
+class DrmConvertedStatus;
+class String8;
+class ActionDescription;
+
+/**
+ * This is the interface class for DRM Manager service.
+ *
+ */
+class IDrmManagerService : public IInterface
+{
+public:
+    enum {
+        ADD_UNIQUEID = IBinder::FIRST_CALL_TRANSACTION,
+        REMOVE_UNIQUEID,
+        LOAD_PLUGINS,
+        LOAD_PLUGINS_FROM_PATH,
+        SET_DRM_SERVICE_LISTENER,
+        UNLOAD_PLUGINS,
+        INSTALL_DRM_ENGINE,
+        GET_CONSTRAINTS_FROM_CONTENT,
+        CAN_HANDLE,
+        PROCESS_DRM_INFO,
+        ACQUIRE_DRM_INFO,
+        SAVE_RIGHTS,
+        GET_ORIGINAL_MIMETYPE,
+        GET_DRM_OBJECT_TYPE,
+        CHECK_RIGHTS_STATUS,
+        CONSUME_RIGHTS,
+        SET_PLAYBACK_STATUS,
+        VALIDATE_ACTION,
+        REMOVE_RIGHTS,
+        REMOVE_ALL_RIGHTS,
+        OPEN_CONVERT_SESSION,
+        CONVERT_DATA,
+        CLOSE_CONVERT_SESSION,
+        GET_ALL_SUPPORT_INFO,
+        OPEN_DECRYPT_SESSION,
+        CLOSE_DECRYPT_SESSION,
+        INITIALIZE_DECRYPT_UNIT,
+        DECRYPT,
+        FINALIZE_DECRYPT_UNIT,
+        PREAD
+    };
+
+public:
+    DECLARE_META_INTERFACE(DrmManagerService);
+
+public:
+    virtual int addUniqueId(int uniqueId) = 0;
+
+    virtual void removeUniqueId(int uniqueId) = 0;
+
+    virtual status_t loadPlugIns(int uniqueId) = 0;
+
+    virtual status_t loadPlugIns(int uniqueId, const String8& plugInDirPath) = 0;
+
+    virtual status_t setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& infoListener) = 0;
+
+    virtual status_t unloadPlugIns(int uniqueId) = 0;
+
+    virtual status_t installDrmEngine(int uniqueId, const String8& drmEngineFile) = 0;
+
+    virtual DrmConstraints* getConstraints(
+            int uniqueId, const String8* path, const int action) = 0;
+
+    virtual bool canHandle(int uniqueId, const String8& path, const String8& mimeType) = 0;
+
+    virtual DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo) = 0;
+
+    virtual DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest) = 0;
+
+    virtual status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) = 0;
+
+    virtual String8 getOriginalMimeType(int uniqueId, const String8& path) = 0;
+
+    virtual int getDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) = 0;
+
+    virtual int checkRightsStatus(int uniqueId, const String8& path, int action) = 0;
+
+    virtual status_t consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+
+    virtual status_t setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) = 0;
+
+    virtual bool validateAction(
+            int uniqueId, const String8& path,
+            int action, const ActionDescription& description) = 0;
+
+    virtual status_t removeRights(int uniqueId, const String8& path) = 0;
+
+    virtual status_t removeAllRights(int uniqueId) = 0;
+
+    virtual int openConvertSession(int uniqueId, const String8& mimeType) = 0;
+
+    virtual DrmConvertedStatus* convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) = 0;
+
+    virtual DrmConvertedStatus* closeConvertSession(int uniqueId, int convertId) = 0;
+
+    virtual status_t getAllSupportInfo(
+            int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) = 0;
+
+    virtual DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length) = 0;
+
+    virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+
+    virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) = 0;
+
+    virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
+
+    virtual status_t finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+
+    virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes,off_t offset) = 0;
+};
+
+/**
+ * This is the Binder implementation class for DRM Manager service.
+ */
+class BpDrmManagerService: public BpInterface<IDrmManagerService>
+{
+public:
+    BpDrmManagerService(const sp<IBinder>& impl)
+            : BpInterface<IDrmManagerService>(impl) {}
+
+    virtual int addUniqueId(int uniqueId);
+
+    virtual void removeUniqueId(int uniqueId);
+
+    virtual status_t loadPlugIns(int uniqueId);
+
+    virtual status_t loadPlugIns(int uniqueId, const String8& plugInDirPath);
+
+    virtual status_t setDrmServiceListener(
+            int uniqueId, const sp<IDrmServiceListener>& infoListener);
+
+    virtual status_t unloadPlugIns(int uniqueId);
+
+    virtual status_t installDrmEngine(int uniqueId, const String8& drmEngineFile);
+
+    virtual DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
+
+    virtual bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
+
+    virtual DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    virtual DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest);
+
+    virtual status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    virtual String8 getOriginalMimeType(int uniqueId, const String8& path);
+
+    virtual int getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    virtual int checkRightsStatus(int uniqueId, const String8& path, int action);
+
+    virtual status_t consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    virtual status_t setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    virtual bool validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    virtual status_t removeRights(int uniqueId, const String8& path);
+
+    virtual status_t removeAllRights(int uniqueId);
+
+    virtual int openConvertSession(int uniqueId, const String8& mimeType);
+
+    virtual DrmConvertedStatus* convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    virtual DrmConvertedStatus* closeConvertSession(int uniqueId, int convertId);
+
+    virtual status_t getAllSupportInfo(
+            int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
+
+    virtual DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
+
+    virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    virtual status_t finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset);
+};
+
+/**
+ * This is the Binder implementation class for DRM Manager service.
+ */
+class BnDrmManagerService: public BnInterface<IDrmManagerService>
+{
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+};
+
+#endif /* __IDRM_MANAGER_SERVICE_H__ */
+
diff --git a/drm/libdrmframework/include/IDrmServiceListener.h b/drm/libdrmframework/include/IDrmServiceListener.h
new file mode 100644
index 0000000..7f7109f
--- /dev/null
+++ b/drm/libdrmframework/include/IDrmServiceListener.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IDRM_SERVICE_LISTENER_H__
+#define __IDRM_SERVICE_LISTENER_H__
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class DrmInfoEvent;
+
+/**
+ * This is the interface class for DRM service listener.
+ *
+ */
+class IDrmServiceListener : public IInterface
+{
+public:
+    enum {
+        NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+    };
+
+public:
+    DECLARE_META_INTERFACE(DrmServiceListener);
+
+public:
+    virtual status_t notify(const DrmInfoEvent& event) = 0;
+};
+
+/**
+ * This is the Binder implementation class for DRM service listener.
+ */
+class BpDrmServiceListener: public BpInterface<IDrmServiceListener>
+{
+public:
+    BpDrmServiceListener(const sp<IBinder>& impl)
+            : BpInterface<IDrmServiceListener>(impl) {}
+
+    virtual status_t notify(const DrmInfoEvent& event);
+};
+
+/**
+ * This is the Binder implementation class for DRM service listener.
+ */
+class BnDrmServiceListener: public BnInterface<IDrmServiceListener>
+{
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+};
+
+#endif /* __IDRM_SERVICE_LISTENER_H__ */
+
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/libdrmframework/include/PlugInManager.h
new file mode 100644
index 0000000..9ad195f
--- /dev/null
+++ b/drm/libdrmframework/include/PlugInManager.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PLUGIN_MANAGER_H__
+#define __PLUGIN_MANAGER_H__
+
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+const char* const PLUGIN_MANAGER_CREATE = "create";
+const char* const PLUGIN_MANAGER_DESTROY = "destroy";
+const char* const PLUGIN_EXTENSION = ".so";
+
+/**
+ * This is the template class for Plugin manager.
+ *
+ * The DrmManager uses this class to handle the plugins.
+ *
+ */
+template<typename Type>
+class TPlugInManager {
+private:
+    typedef void*      HANDLE;
+    typedef Type*      create_t(void);
+    typedef void       destroy_t(Type*);
+    typedef create_t*  FPCREATE;
+    typedef destroy_t* FPDESTORY;
+
+    typedef struct _PlugInContainer {
+        String8   sPath;
+        HANDLE    hHandle;
+        FPCREATE  fpCreate;
+        FPDESTORY fpDestory;
+        Type*     pInstance;
+
+        _PlugInContainer():
+            sPath("")
+            ,hHandle(NULL)
+            ,fpCreate(NULL)
+            ,fpDestory(NULL)
+            ,pInstance(NULL)
+            {}
+    } PlugInContainer;
+
+    typedef KeyedVector<String8, PlugInContainer*> PlugInMap;
+    PlugInMap m_plugInMap;
+
+    typedef Vector<String8> PlugInIdList;
+    PlugInIdList m_plugInIdList;
+
+public:
+    /**
+     * Load all the plug-ins in the specified directory
+     *
+     * @param[in] rsPlugInDirPath
+     *     Directory path which plug-ins (dynamic library) are stored
+     * @note Plug-ins should be implemented according to the specification
+     */
+    void loadPlugIns(const String8& rsPlugInDirPath) {
+        Vector<String8> plugInFileList = getPlugInPathList(rsPlugInDirPath);
+
+        if (!plugInFileList.isEmpty()) {
+            for (unsigned int i = 0; i < plugInFileList.size(); ++i) {
+                loadPlugIn(plugInFileList[i]);
+            }
+        }
+    }
+
+    /**
+     * Unload all the plug-ins
+     *
+     */
+    void unloadPlugIns() {
+        for (unsigned int i = 0; i < m_plugInIdList.size(); ++i) {
+            unloadPlugIn(m_plugInIdList[i]);
+        }
+        m_plugInIdList.clear();
+    }
+
+    /**
+     * Get all the IDs of available plug-ins
+     *
+     * @return[in] plugInIdList
+     *     String type Vector in which all plug-in IDs are stored
+     */
+    Vector<String8> getPlugInIdList() const {
+        return m_plugInIdList;
+    }
+
+    /**
+     * Get a plug-in reference of specified ID
+     *
+     * @param[in] rsPlugInId
+     *     Plug-in ID to be used
+     * @return plugIn
+     *     Reference of specified plug-in instance
+     */
+    Type& getPlugIn(const String8& rsPlugInId) {
+        if (!contains(rsPlugInId)) {
+            // This error case never happens
+        }
+        return *(m_plugInMap.valueFor(rsPlugInId)->pInstance);
+    }
+
+public:
+    /**
+     * Load a plug-in stored in the specified path
+     *
+     * @param[in] rsPlugInPath
+     *     Plug-in (dynamic library) file path
+     * @note Plug-in should be implemented according to the specification
+     */
+    void loadPlugIn(const String8& rsPlugInPath) {
+        if (contains(rsPlugInPath)) {
+            return;
+        }
+
+        PlugInContainer* pPlugInContainer = new PlugInContainer();
+
+        pPlugInContainer->hHandle = dlopen(rsPlugInPath.string(), RTLD_LAZY);
+
+        if (NULL == pPlugInContainer->hHandle) {
+            delete pPlugInContainer;
+            pPlugInContainer = NULL;
+            return;
+        }
+
+        pPlugInContainer->sPath = rsPlugInPath;
+        pPlugInContainer->fpCreate
+                = (FPCREATE)dlsym(pPlugInContainer->hHandle, PLUGIN_MANAGER_CREATE);
+        pPlugInContainer->fpDestory
+                = (FPDESTORY)dlsym(pPlugInContainer->hHandle, PLUGIN_MANAGER_DESTROY);
+
+        if (NULL != pPlugInContainer->fpCreate && NULL != pPlugInContainer->fpDestory) {
+            pPlugInContainer->pInstance = (Type*)pPlugInContainer->fpCreate();
+            m_plugInIdList.add(rsPlugInPath);
+            m_plugInMap.add(rsPlugInPath, pPlugInContainer);
+        } else {
+            dlclose(pPlugInContainer->hHandle);
+            delete pPlugInContainer;
+            pPlugInContainer = NULL;
+            return;
+        }
+    }
+
+    /**
+     * Unload a plug-in stored in the specified path
+     *
+     * @param[in] rsPlugInPath
+     *     Plug-in (dynamic library) file path
+     */
+    void unloadPlugIn(const String8& rsPlugInPath) {
+        if (!contains(rsPlugInPath)) {
+            return;
+        }
+
+        PlugInContainer* pPlugInContainer = m_plugInMap.valueFor(rsPlugInPath);
+        pPlugInContainer->fpDestory(pPlugInContainer->pInstance);
+        dlclose(pPlugInContainer->hHandle);
+
+        m_plugInMap.removeItem(rsPlugInPath);
+        delete pPlugInContainer;
+        pPlugInContainer = NULL;
+    }
+
+private:
+    /**
+     * True if TPlugInManager contains rsPlugInId
+     */
+    bool contains(const String8& rsPlugInId) {
+        return m_plugInMap.indexOfKey(rsPlugInId) != NAME_NOT_FOUND;
+    }
+
+    /**
+     * Return file path list of plug-ins stored in the specified directory
+     *
+     * @param[in] rsDirPath
+     *     Directory path in which plug-ins are stored
+     * @return plugInFileList
+     *     String type Vector in which file path of plug-ins are stored
+     */
+    Vector<String8> getPlugInPathList(const String8& rsDirPath) {
+        Vector<String8> fileList;
+        DIR* pDir = opendir(rsDirPath.string());
+        struct dirent* pEntry = new dirent();
+
+        while (NULL != pDir && NULL != (pEntry = readdir(pDir))) {
+            if (!isPlugIn(pEntry)) {
+                continue;
+            }
+            String8 plugInPath;
+            plugInPath += rsDirPath;
+            plugInPath += "/";
+            plugInPath += pEntry->d_name;
+
+            fileList.add(plugInPath);
+        }
+
+        if (NULL != pDir) {
+            closedir(pDir);
+        }
+        delete pEntry;
+        pEntry = NULL;
+
+        return fileList;
+    }
+
+    /**
+     * True if the input name denotes plug-in
+     */
+    bool isPlugIn(const struct dirent* pEntry) const {
+        String8 sName(pEntry->d_name);
+        int extentionPos = sName.size() - String8(PLUGIN_EXTENSION).size();
+        if (extentionPos < 0) {
+            return false;
+        }
+        return extentionPos == (int)sName.find(PLUGIN_EXTENSION);
+    }
+
+    /**
+     * True if the input entry is "." or ".."
+     */
+    bool isDotOrDDot(const struct dirent* pEntry) const {
+        String8 sName(pEntry->d_name);
+        return "." == sName || ".." == sName;
+    }
+
+    /**
+     * True if input entry is directory
+     */
+    bool isDirectory(const struct dirent* pEntry) const {
+        return DT_DIR == pEntry->d_type;
+    }
+
+    /**
+     * True if input entry is regular file
+     */
+    bool isRegularFile(const struct dirent* pEntry) const {
+        return DT_REG == pEntry->d_type;
+    }
+
+    /**
+     * True if input entry is link
+     */
+    bool isLink(const struct dirent* pEntry) const {
+        return DT_LNK == pEntry->d_type;
+    }
+};
+
+};
+
+#endif /* __PLUGIN_MANAGER_H__ */
+
diff --git a/drm/libdrmframework/include/ReadWriteUtils.h b/drm/libdrmframework/include/ReadWriteUtils.h
new file mode 100644
index 0000000..529b342
--- /dev/null
+++ b/drm/libdrmframework/include/ReadWriteUtils.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __READ_WRITE_UTILS_H__
+#define __READ_WRITE_UTILS_H__
+
+#include <utils/FileMap.h>
+#include <drm/drm_framework_common.h>
+
+namespace android {
+
+/**
+ * This is an utility class which performs IO operations.
+ *
+ */
+class ReadWriteUtils {
+public:
+    /**
+     * Constructor for ReadWriteUtils
+     */
+    ReadWriteUtils() {}
+
+    /**
+     * Destructor for ReadWriteUtils
+     */
+    virtual ~ReadWriteUtils();
+
+public:
+    /**
+     * Reads the data from the file path provided
+     *
+     * @param[in] filePath Path of the file
+     * @return Data read from the file
+     */
+    static String8 readBytes(const String8& filePath);
+    /**
+     * Reads the data into the given buffer from the file path provided
+     *
+     * @param[in] filePath Path of the file
+     * @param[out] buffer Data read from the file
+     * @return Length of the data read from the file
+     */
+    static int readBytes(const String8& filePath, char** buffer);
+    /**
+     * Writes the data into the file path provided
+     *
+     * @param[in] filePath Path of the file
+     * @param[in] dataBuffer Data to write
+     */
+    static void writeToFile(const String8& filePath, const String8& data);
+    /**
+     * Appends the data into the file path provided
+     *
+     * @param[in] filePath Path of the file
+     * @param[in] dataBuffer Data to append
+     */
+    static void appendToFile(const String8& filePath, const String8& data);
+
+private:
+    FileMap* mFileMap;
+};
+
+};
+
+#endif /* __READ_WRITE_UTILS_H__ */
+
diff --git a/drm/libdrmframework/include/StringTokenizer.h b/drm/libdrmframework/include/StringTokenizer.h
new file mode 100644
index 0000000..70e7558
--- /dev/null
+++ b/drm/libdrmframework/include/StringTokenizer.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __STRING_TOKENIZER_H__
+#define __STRING_TOKENIZER_H__
+
+#include <drm/drm_framework_common.h>
+
+namespace android {
+
+/**
+ * This is an utility class for String manipulation.
+ *
+ */
+class StringTokenizer {
+public:
+    /**
+     * Iterator for string tokens
+     */
+    class Iterator {
+        friend class StringTokenizer;
+    private:
+        Iterator(StringTokenizer* StringTokenizer)
+         : mStringTokenizer(StringTokenizer), mIndex(0) {}
+
+    public:
+        Iterator(const Iterator& iterator);
+        Iterator& operator=(const Iterator& iterator);
+        virtual ~Iterator() {}
+
+    public:
+        bool hasNext();
+        String8& next();
+
+    private:
+        StringTokenizer* mStringTokenizer;
+        unsigned int mIndex;
+    };
+
+public:
+    /**
+     * Constructor for StringTokenizer
+     *
+     * @param[in] string Complete string data
+     * @param[in] delimeter Delimeter used to split the string
+     */
+    StringTokenizer(const String8& string, const String8& delimeter);
+
+    /**
+     * Destructor for StringTokenizer
+     */
+    ~StringTokenizer() {}
+
+private:
+    /**
+     * Splits the string according to the delimeter
+     */
+    void splitString(const String8& string, const String8& delimeter);
+
+public:
+    /**
+     * Returns Iterator object to walk through the split string values
+     *
+     * @return Iterator object
+     */
+    Iterator iterator();
+
+private:
+    Vector<String8> mStringTokenizerVector;
+};
+
+};
+#endif /* __STRING_TOKENIZER_H__ */
+
diff --git a/drm/libdrmframework/plugins/Android.mk b/drm/libdrmframework/plugins/Android.mk
new file mode 100644
index 0000000..9ee7961
--- /dev/null
+++ b/drm/libdrmframework/plugins/Android.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
new file mode 100644
index 0000000..b355534
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_ENGINE_BASE_H__
+#define __DRM_ENGINE_BASE_H__
+
+#include <drm/drm_framework_common.h>
+#include "IDrmEngine.h"
+
+namespace android {
+
+/**
+ * This class is an interface for plug-in developers
+ *
+ * Responsibility of this class is control the sequence of actual plug-in.
+ * All each plug-in developer has to do is implement onXXX() type virtual interfaces.
+ */
+class DrmEngineBase : public IDrmEngine {
+public:
+    DrmEngineBase();
+    virtual ~DrmEngineBase();
+
+public:
+    DrmConstraints* getConstraints(int uniqueId, const String8* path, int action);
+
+    status_t initialize(int uniqueId);
+
+    status_t setOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
+
+    status_t terminate(int uniqueId);
+
+    bool canHandle(int uniqueId, const String8& path);
+
+    DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
+
+    String8 getOriginalMimeType(int uniqueId, const String8& path);
+
+    int getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    int checkRightsStatus(int uniqueId, const String8& path, int action);
+
+    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    status_t setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    status_t removeRights(int uniqueId, const String8& path);
+
+    status_t removeAllRights(int uniqueId);
+
+    status_t openConvertSession(int uniqueId, int convertId);
+
+    DrmConvertedStatus* convertData(int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    DrmConvertedStatus* closeConvertSession(int uniqueId, int convertId);
+
+    DrmSupportInfo* getSupportInfo(int uniqueId);
+
+    status_t openDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length);
+
+    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset);
+
+protected:
+    /////////////////////////////////////////////////////
+    // Interface for plug-in developers                //
+    // each plug-in has to implement following method  //
+    /////////////////////////////////////////////////////
+    /**
+     * Get constraint information associated with input content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Actions defined such as,
+     *     Action::DEFAULT, Action::PLAY, etc
+     * @return DrmConstraints
+     *     key-value pairs of constraint are embedded in it
+     * @note
+     *     In case of error, return NULL
+     */
+    virtual DrmConstraints* onGetConstraints(
+            int uniqueId, const String8* path, int action) = 0;
+
+    /**
+     * Initialize plug-in
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onInitialize(int uniqueId) = 0;
+
+    /**
+     * Register a callback to be invoked when the caller required to
+     * receive necessary information
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] infoListener Listener
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onSetOnInfoListener(
+            int uniqueId, const IDrmEngine::OnInfoListener* infoListener) = 0;
+
+    /**
+     * Terminate the plug-in
+     * and release resource bound to plug-in
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onTerminate(int uniqueId) = 0;
+
+    /**
+     * Get whether the given content can be handled by this plugin or not
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path the protected object
+     * @return bool
+     *     Returns true if this plugin can handle , false in case of not able to handle
+     */
+    virtual bool onCanHandle(int uniqueId, const String8& path) = 0;
+
+    /**
+     * Executes given drm information based on its type
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmInfo Information needs to be processed
+     * @return DrmInfoStatus
+     *     instance as a result of processing given input
+     */
+    virtual DrmInfoStatus* onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) = 0;
+
+    /**
+     * Save DRM rights to specified rights path
+     * and make association with content path
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmRights DrmRights to be saved
+     * @param[in] rightsPath File path where rights to be saved
+     * @param[in] contentPath File path where content was saved
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onSaveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightspath, const String8& contentPath) = 0;
+
+    /**
+     * Retrieves necessary information for registration, unregistration or rights
+     * acquisition information.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmInfoRequest Request information to retrieve drmInfo
+     * @return DrmInfo
+     *     instance as a result of processing given input
+     */
+    virtual DrmInfo* onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest) = 0;
+
+    /**
+     * Retrieves the mime type embedded inside the original content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return String8
+     *     Returns mime-type of the original content, such as "video/mpeg"
+     */
+    virtual String8 onGetOriginalMimeType(int uniqueId, const String8& path) = 0;
+
+    /**
+     * Retrieves the type of the protected object (content, rights, etc..)
+     * using specified path or mimetype. At least one parameter should be non null
+     * to retrieve DRM object type
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the content or null.
+     * @param[in] mimeType Mime type of the content or null.
+     * @return type of the DRM content,
+     *     such as DrmObjectType::CONTENT, DrmObjectType::RIGHTS_OBJECT
+     */
+    virtual int onGetDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) = 0;
+
+    /**
+     * Check whether the given content has valid rights or not
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to perform (Action::DEFAULT, Action::PLAY, etc)
+     * @return the status of the rights for the protected content,
+     *     such as RightsStatus::RIGHTS_VALID, RightsStatus::RIGHTS_EXPIRED, etc.
+     */
+    virtual int onCheckRightsStatus(int uniqueId, const String8& path, int action) = 0;
+
+    /**
+     * Consumes the rights for a content.
+     * If the reserve parameter is true the rights is reserved until the same
+     * application calls this api again with the reserve parameter set to false.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
+     * @param[in] reserve True if the rights should be reserved.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+            int action, bool reserve) = 0;
+
+    /**
+     * Informs the DRM Engine about the playback actions performed on the DRM files.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
+     * @param[in] position Position in the file (in milliseconds) where the start occurs.
+     *     Only valid together with Playback::START.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onSetPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) = 0;
+
+    /**
+     * Validates whether an action on the DRM content is allowed or not.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to validate (Action::PLAY, Action::TRANSFER, etc)
+     * @param[in] description Detailed description of the action
+     * @return true if the action is allowed.
+     */
+    virtual bool onValidateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description) = 0;
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onRemoveRights(int uniqueId, const String8& path) = 0;
+
+    /**
+     * Removes all the rights information of each plug-in associated with
+     * DRM framework. Will be used in master reset
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onRemoveAllRights(int uniqueId) = 0;
+
+    /**
+     * This API is for Forward Lock based DRM scheme.
+     * Each time the application tries to download a new DRM file
+     * which needs to be converted, then the application has to
+     * begin with calling this API.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onOpenConvertSession(int uniqueId, int convertId) = 0;
+
+    /**
+     * Accepts and converts the input data which is part of DRM file.
+     * The resultant converted data and the status is returned in the DrmConvertedInfo
+     * object. This method will be called each time there are new block
+     * of data received by the application.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @param[in] inputData Input Data which need to be converted
+     * @return Return object contains the status of the data conversion,
+     *     the output converted data and offset. In this case the
+     *     application will ignore the offset information.
+     */
+    virtual DrmConvertedStatus* onConvertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) = 0;
+
+    /**
+     * Informs the Drm Agent when there is no more data which need to be converted
+     * or when an error occurs. Upon successful conversion of the complete data,
+     * the agent will inform that where the header and body signature
+     * should be added. This signature appending is needed to integrity
+     * protect the converted file.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @return Return object contains the status of the data conversion,
+     *     the header and body signature data. It also informs
+     *     the application on which offset these signature data
+     *     should be appended.
+     */
+    virtual DrmConvertedStatus* onCloseConvertSession(int uniqueId, int convertId) = 0;
+
+    /**
+     * Returns the information about the Drm Engine capabilities which includes
+     * supported MimeTypes and file suffixes.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return DrmSupportInfo
+     *     instance which holds the capabilities of a plug-in
+     */
+    virtual DrmSupportInfo* onGetSupportInfo(int uniqueId) = 0;
+
+    /**
+     * Open the decrypt session to decrypt the given protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the current decryption session
+     * @param[in] fd File descriptor of the protected content to be decrypted
+     * @param[in] offset Start position of the content
+     * @param[in] length The length of the protected content
+     * @return
+     *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
+     */
+    virtual status_t onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length) = 0;
+
+    /**
+     * Close the decrypt session for the given handle
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+
+    /**
+     * Initialize decryption for the given unit of the protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptId Handle for the decryption session
+     * @param[in] decryptUnitId ID Specifies decryption unit, such as track ID
+     * @param[in] headerInfo Information for initializing decryption of this decrypUnit
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) = 0;
+
+    /**
+     * Decrypt the protected content buffers for the given unit
+     * This method will be called any number of times, based on number of
+     * encrypted streams received from application.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptId Handle for the decryption session
+     * @param[in] decryptUnitId ID Specifies decryption unit, such as track ID
+     * @param[in] encBuffer Encrypted data block
+     * @param[out] decBuffer Decrypted data block
+     * @param[in] IV Optional buffer
+     * @return status_t
+     *     Returns the error code for this API
+     *     DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
+     *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
+     *     DRM_ERROR_DECRYPT for failure.
+     */
+    virtual status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
+
+    /**
+     * Finalize decryption for the given unit of the protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID Specifies decryption unit, such as track ID
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t onFinalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+
+    /**
+     * Reads the specified number of bytes from an open DRM file.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[out] buffer Reference to the buffer that should receive the read data.
+     * @param[in] numBytes Number of bytes to read.
+     * @param[in] offset Offset with which to update the file position.
+     *
+     * @return Number of bytes read. Returns -1 for Failure.
+     */
+    virtual ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset) = 0;
+};
+
+};
+
+#endif /* __DRM_ENGINE_BASE_H__ */
+
diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
new file mode 100644
index 0000000..b711500
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IDRM_ENGINE_H__
+#define __IDRM_ENGINE_H__
+
+#include <drm/drm_framework_common.h>
+
+namespace android {
+
+class DrmContentIds;
+class DrmConstraints;
+class DrmRights;
+class DrmInfo;
+class DrmInfoStatus;
+class DrmConvertedStatus;
+class DrmInfoRequest;
+class DrmSupportInfo;
+class DrmInfoEvent;
+
+/**
+ * This class is an interface for plug-in user
+ *
+ * Responsibility of this class is provide generic interface to DRM Engine Manager.
+ * Each interface need to be as abstract as possible.
+ */
+class IDrmEngine {
+public:
+    virtual ~IDrmEngine() {
+    }
+
+public:
+    class OnInfoListener {
+
+    public:
+        virtual void onInfo(const DrmInfoEvent& event) = 0;
+
+        virtual ~OnInfoListener() { }
+    };
+
+public:
+
+    //////////////////////////////////
+    // Implementation of IDrmEngine //
+    //////////////////////////////////
+
+    /**
+     * Initialize plug-in
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t initialize(int uniqueId) = 0;
+
+    /**
+     * Register a callback to be invoked when the caller required to
+     * receive necessary information
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] infoListener Listener
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t setOnInfoListener(
+            int uniqueId, const IDrmEngine::OnInfoListener* infoListener) = 0;
+
+    /**
+     * Terminate the plug-in
+     * and release resource bound to plug-in
+     * e.g.) release native resource
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t terminate(int uniqueId) = 0;
+
+    /**
+     * Get constraint information associated with input content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Actions defined such as,
+     *     Action::DEFAULT, Action::PLAY, etc
+     * @return DrmConstraints
+     *     key-value pairs of constraint are embedded in it
+     * @note
+     *     In case of error, return NULL
+     */
+    virtual DrmConstraints* getConstraints(
+            int uniqueId, const String8* path, int action) = 0;
+
+    /**
+     * Get whether the given content can be handled by this plugin or not
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path the protected object
+     * @return bool
+     *     true if this plugin can handle , false in case of not able to handle
+     */
+    virtual bool canHandle(int uniqueId, const String8& path) = 0;
+
+    /**
+     * Executes given drm information based on its type
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmInfo Information needs to be processed
+     * @return DrmInfoStatus
+     *     instance as a result of processing given input
+     */
+    virtual DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo) = 0;
+
+    /**
+     * Retrieves necessary information for registration, unregistration or rights
+     * acquisition information.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmInfoRequest Request information to retrieve drmInfo
+     * @return DrmInfo
+     *     instance as a result of processing given input
+     */
+    virtual DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) = 0;
+
+    /**
+     * Save DRM rights to specified rights path
+     * and make association with content path
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] drmRights DrmRights to be saved
+     * @param[in] rightsPath File path where rights to be saved
+     * @param[in] contentPath File path where content was saved
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) = 0;
+
+    /**
+     * Retrieves the mime type embedded inside the original content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return String8
+     *     Returns mime-type of the original content, such as "video/mpeg"
+     */
+    virtual String8 getOriginalMimeType(int uniqueId, const String8& path) = 0;
+
+    /**
+     * Retrieves the type of the protected object (content, rights, etc..)
+     * using specified path or mimetype. At least one parameter should be non null
+     * to retrieve DRM object type
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the content or null.
+     * @param[in] mimeType Mime type of the content or null.
+     * @return type of the DRM content,
+     *     such as DrmObjectType::CONTENT, DrmObjectType::RIGHTS_OBJECT
+     */
+    virtual int getDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) = 0;
+
+    /**
+     * Check whether the given content has valid rights or not
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to perform (Action::DEFAULT, Action::PLAY, etc)
+     * @return the status of the rights for the protected content,
+     *     such as RightsStatus::RIGHTS_VALID, RightsStatus::RIGHTS_EXPIRED, etc.
+     */
+    virtual int checkRightsStatus(int uniqueId, const String8& path, int action) = 0;
+
+    /**
+     * Consumes the rights for a content.
+     * If the reserve parameter is true the rights is reserved until the same
+     * application calls this api again with the reserve parameter set to false.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
+     * @param[in] reserve True if the rights should be reserved.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+
+    /**
+     * Informs the DRM Engine about the playback actions performed on the DRM files.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
+     * @param[in] position Position in the file (in milliseconds) where the start occurs.
+     *     Only valid together with Playback::START.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t setPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+            int playbackStatus, int position) = 0;
+
+    /**
+     * Validates whether an action on the DRM content is allowed or not.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to validate (Action::PLAY, Action::TRANSFER, etc)
+     * @param[in] description Detailed description of the action
+     * @return true if the action is allowed.
+     */
+    virtual bool validateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description) = 0;
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t removeRights(int uniqueId, const String8& path) = 0;
+
+    /**
+     * Removes all the rights information of each plug-in associated with
+     * DRM framework. Will be used in master reset
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t removeAllRights(int uniqueId) = 0;
+
+    /**
+     * This API is for Forward Lock based DRM scheme.
+     * Each time the application tries to download a new DRM file
+     * which needs to be converted, then the application has to
+     * begin with calling this API.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t openConvertSession(int uniqueId, int convertId) = 0;
+
+    /**
+     * Accepts and converts the input data which is part of DRM file.
+     * The resultant converted data and the status is returned in the DrmConvertedInfo
+     * object. This method will be called each time there are new block
+     * of data received by the application.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @param[in] inputData Input Data which need to be converted
+     * @return Return object contains the status of the data conversion,
+     *     the output converted data and offset. In this case the
+     *     application will ignore the offset information.
+     */
+    virtual DrmConvertedStatus* convertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) = 0;
+
+    /**
+     * Informs the Drm Agent when there is no more data which need to be converted
+     * or when an error occurs. Upon successful conversion of the complete data,
+     * the agent will inform that where the header and body signature
+     * should be added. This signature appending is needed to integrity
+     * protect the converted file.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] convertId Handle for the convert session
+     * @return Return object contains the status of the data conversion,
+     *     the header and body signature data. It also informs
+     *     the application on which offset these signature data
+     *     should be appended.
+     */
+    virtual DrmConvertedStatus* closeConvertSession( int uniqueId, int convertId) = 0;
+
+    /**
+     * Returns the information about the Drm Engine capabilities which includes
+     * supported MimeTypes and file suffixes.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @return DrmSupportInfo
+     *     instance which holds the capabilities of a plug-in
+     */
+    virtual DrmSupportInfo* getSupportInfo(int uniqueId) = 0;
+
+    /**
+     * Open the decrypt session to decrypt the given protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the current decryption session
+     * @param[in] fd File descriptor of the protected content to be decrypted
+     * @param[in] offset Start position of the content
+     * @param[in] length The length of the protected content
+     * @return
+     *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
+     */
+    virtual status_t openDecryptSession(
+        int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length) = 0;
+
+    /**
+     * Close the decrypt session for the given handle
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+
+    /**
+     * Initialize decryption for the given unit of the protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @param[in] headerInfo Information for initializing decryption of this decrypUnit
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) = 0;
+
+    /**
+     * Decrypt the protected content buffers for the given unit
+     * This method will be called any number of times, based on number of
+     * encrypted streams received from application.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @param[in] encBuffer Encrypted data block
+     * @param[out] decBuffer Decrypted data block
+     * @param[in] IV Optional buffer
+     * @return status_t
+     *     Returns the error code for this API
+     *     DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
+     *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
+     *     DRM_ERROR_DECRYPT for failure.
+     */
+    virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
+
+    /**
+     * Finalize decryption for the given unit of the protected content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    virtual status_t finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+
+    /**
+     * Reads the specified number of bytes from an open DRM file.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[out] buffer Reference to the buffer that should receive the read data.
+     * @param[in] numBytes Number of bytes to read.
+     * @param[in] offset Offset with which to update the file position.
+     *
+     * @return Number of bytes read. Returns -1 for Failure.
+     */
+    virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset) = 0;
+};
+
+};
+
+#endif /* __IDRM_ENGINE_H__ */
+
diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk
new file mode 100644
index 0000000..7856d37
--- /dev/null
+++ b/drm/libdrmframework/plugins/passthru/Android.mk
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    src/DrmPassthruPlugIn.cpp
+
+LOCAL_MODULE := libdrmpassthruplugin
+
+LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_C_INCLUDES += \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/plugins/passthru/include \
+    $(TOP)/frameworks/base/drm/libdrmframework/plugins/common/include \
+    $(TOP)/frameworks/base/include
+
+# Set the following flag to enable the decryption passthru flow
+#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
new file mode 100644
index 0000000..eed1628
--- /dev/null
+++ b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_PASSTHRU_PLUGIN_H__
+#define __DRM_PASSTHRU_PLUGIN_H__
+
+#include <DrmEngineBase.h>
+
+namespace android {
+
+class DrmPassthruPlugIn : public DrmEngineBase {
+
+public:
+    DrmPassthruPlugIn();
+    virtual ~DrmPassthruPlugIn();
+
+protected:
+    DrmConstraints* onGetConstraints(int uniqueId, const String8* path, int action);
+
+    status_t onInitialize(int uniqueId);
+
+    status_t onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
+
+    status_t onTerminate(int uniqueId);
+
+    bool onCanHandle(int uniqueId, const String8& path);
+
+    DrmInfoStatus* onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    status_t onSaveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    DrmInfo* onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
+
+    String8 onGetOriginalMimeType(int uniqueId, const String8& path);
+
+    int onGetDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    int onCheckRightsStatus(int uniqueId, const String8& path, int action);
+
+    status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    status_t onSetPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool onValidateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    status_t onRemoveRights(int uniqueId, const String8& path);
+
+    status_t onRemoveAllRights(int uniqueId);
+
+    status_t onOpenConvertSession(int uniqueId, int convertId);
+
+    DrmConvertedStatus* onConvertData(int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    DrmConvertedStatus* onCloseConvertSession(int uniqueId, int convertId);
+
+    DrmSupportInfo* onGetSupportInfo(int uniqueId);
+
+    status_t onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length);
+
+    status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    status_t onFinalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset);
+
+private:
+    DecryptHandle* openDecryptSessionImpl();
+};
+
+};
+
+#endif /* __DRM_PASSTHRU_PLUGIN_H__ */
+
diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
new file mode 100644
index 0000000..4c7714d
--- /dev/null
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "DrmPassthruPlugIn"
+#include <utils/Log.h>
+
+#include <drm/DrmRights.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmInfo.h>
+#include <drm/DrmInfoEvent.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmConvertedStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+#include <DrmPassthruPlugIn.h>
+
+using namespace android;
+
+
+// This extern "C" is mandatory to be managed by TPlugInManager
+extern "C" IDrmEngine* create() {
+    return new DrmPassthruPlugIn();
+}
+
+// This extern "C" is mandatory to be managed by TPlugInManager
+extern "C" void destroy(IDrmEngine* pPlugIn) {
+    delete pPlugIn;
+    pPlugIn = NULL;
+}
+
+DrmPassthruPlugIn::DrmPassthruPlugIn()
+    : DrmEngineBase() {
+
+}
+
+DrmPassthruPlugIn::~DrmPassthruPlugIn() {
+
+}
+
+DrmConstraints* DrmPassthruPlugIn::onGetConstraints(
+        int uniqueId, const String8* path, int action) {
+    LOGD("DrmPassthruPlugIn::onGetConstraints From Path: %d", uniqueId);
+    DrmConstraints* drmConstraints = new DrmConstraints();
+
+    String8 value("dummy_available_time");
+    char* charValue = NULL;
+    charValue = new char[value.length() + 1];
+    strncpy(charValue, value.string(), value.length());
+
+    //Just add dummy available time for verification
+    drmConstraints->put(&(DrmConstraints::LICENSE_AVAILABLE_TIME), charValue);
+
+    return drmConstraints;
+}
+
+DrmInfoStatus* DrmPassthruPlugIn::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    LOGD("DrmPassthruPlugIn::onProcessDrmInfo - Enter : %d", uniqueId);
+    DrmInfoStatus* drmInfoStatus = NULL;
+    if (NULL != drmInfo) {
+        switch (drmInfo->getInfoType()) {
+        case DrmInfoRequest::TYPE_REGISTRATION_INFO: {
+            const DrmBuffer* emptyBuffer = new DrmBuffer();
+            drmInfoStatus
+                = new DrmInfoStatus(DrmInfoStatus::STATUS_OK, emptyBuffer, drmInfo->getMimeType());
+            break;
+        }
+        case DrmInfoRequest::TYPE_UNREGISTRATION_INFO: {
+            const DrmBuffer* emptyBuffer = new DrmBuffer();
+            drmInfoStatus
+                = new DrmInfoStatus(DrmInfoStatus::STATUS_OK, emptyBuffer, drmInfo->getMimeType());
+            break;
+        }
+        case DrmInfoRequest::TYPE_RIGHTS_ACQUISITION_INFO: {
+            String8 licenseString("dummy_license_string");
+            const int bufferSize = licenseString.size();
+            char* data = NULL;
+            data = new char[bufferSize];
+            memcpy(data, licenseString.string(), bufferSize);
+            const DrmBuffer* buffer = new DrmBuffer(data, bufferSize);
+            drmInfoStatus
+                = new DrmInfoStatus(DrmInfoStatus::STATUS_OK, buffer, drmInfo->getMimeType());
+            break;
+        }
+        }
+    }
+    LOGD("DrmPassthruPlugIn::onProcessDrmInfo - Exit");
+    return drmInfoStatus;
+}
+
+status_t DrmPassthruPlugIn::onSetOnInfoListener(
+            int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
+    LOGD("DrmPassthruPlugIn::onSetOnInfoListener : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onInitialize(int uniqueId) {
+    LOGD("DrmPassthruPlugIn::onInitialize : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onTerminate(int uniqueId) {
+    LOGD("DrmPassthruPlugIn::onTerminate : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+DrmSupportInfo* DrmPassthruPlugIn::onGetSupportInfo(int uniqueId) {
+    LOGD("DrmPassthruPlugIn::onGetSupportInfo : %d", uniqueId);
+    DrmSupportInfo* drmSupportInfo = new DrmSupportInfo();
+    // Add mimetype's
+    drmSupportInfo->addMimeType(String8("application/vnd.passthru.drm"));
+    // Add File Suffixes
+    drmSupportInfo->addFileSuffix(String8(".passthru"));
+    // Add plug-in description
+    drmSupportInfo->setDescription(String8("Passthru plug-in"));
+    return drmSupportInfo;
+}
+
+status_t DrmPassthruPlugIn::onSaveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    LOGD("DrmPassthruPlugIn::onSaveRights : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+DrmInfo* DrmPassthruPlugIn::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    LOGD("DrmPassthruPlugIn::onAcquireDrmInfo : %d", uniqueId);
+    DrmInfo* drmInfo = NULL;
+
+    if (NULL != drmInfoRequest) {
+        String8 dataString("dummy_acquistion_string");
+        int length = dataString.length();
+        char* data = NULL;
+        data = new char[length];
+        memcpy(data, dataString.string(), length);
+        drmInfo = new DrmInfo(drmInfoRequest->getInfoType(),
+            DrmBuffer(data, length), drmInfoRequest->getMimeType());
+    }
+    return drmInfo;
+}
+
+bool DrmPassthruPlugIn::onCanHandle(int uniqueId, const String8& path) {
+    LOGD("DrmPassthruPlugIn::canHandle: %s ", path.string());
+    String8 extension = path.getPathExtension();
+    extension.toLower();
+    return (String8(".passthru") == extension);
+}
+
+String8 DrmPassthruPlugIn::onGetOriginalMimeType(int uniqueId, const String8& path) {
+    LOGD("DrmPassthruPlugIn::onGetOriginalMimeType() : %d", uniqueId);
+    return String8("video/passthru");
+}
+
+int DrmPassthruPlugIn::onGetDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) {
+    LOGD("DrmPassthruPlugIn::onGetDrmObjectType() : %d", uniqueId);
+    return DrmObjectType::UNKNOWN;
+}
+
+int DrmPassthruPlugIn::onCheckRightsStatus(int uniqueId, const String8& path, int action) {
+    LOGD("DrmPassthruPlugIn::onCheckRightsStatus() : %d", uniqueId);
+    int rightsStatus = RightsStatus::RIGHTS_VALID;
+    return rightsStatus;
+}
+
+status_t DrmPassthruPlugIn::onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+            int action, bool reserve) {
+    LOGD("DrmPassthruPlugIn::onConsumeRights() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+            int playbackStatus, int position) {
+    LOGD("DrmPassthruPlugIn::onSetPlaybackStatus() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+bool DrmPassthruPlugIn::onValidateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description) {
+    LOGD("DrmPassthruPlugIn::onValidateAction() : %d", uniqueId);
+    return true;
+}
+
+status_t DrmPassthruPlugIn::onRemoveRights(int uniqueId, const String8& path) {
+    LOGD("DrmPassthruPlugIn::onRemoveRights() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onRemoveAllRights(int uniqueId) {
+    LOGD("DrmPassthruPlugIn::onRemoveAllRights() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onOpenConvertSession(int uniqueId, int convertId) {
+    LOGD("DrmPassthruPlugIn::onOpenConvertSession() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+DrmConvertedStatus* DrmPassthruPlugIn::onConvertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) {
+    LOGD("DrmPassthruPlugIn::onConvertData() : %d", uniqueId);
+    DrmBuffer* convertedData = NULL;
+
+    if (NULL != inputData && 0 < inputData->length) {
+        int length = inputData->length;
+        char* data = NULL;
+        data = new char[length];
+        convertedData = new DrmBuffer(data, length);
+        memcpy(convertedData->data, inputData->data, length);
+    }
+    return new DrmConvertedStatus(DrmConvertedStatus::STATUS_OK, convertedData, 0 /*offset*/);
+}
+
+DrmConvertedStatus* DrmPassthruPlugIn::onCloseConvertSession(int uniqueId, int convertId) {
+    LOGD("DrmPassthruPlugIn::onCloseConvertSession() : %d", uniqueId);
+    return new DrmConvertedStatus(DrmConvertedStatus::STATUS_OK, NULL, 0 /*offset*/);
+}
+
+status_t DrmPassthruPlugIn::onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length) {
+    LOGD("DrmPassthruPlugIn::onOpenDecryptSession() : %d", uniqueId);
+
+#ifdef ENABLE_PASSTHRU_DECRYPTION
+    decryptHandle->mimeType = String8("video/passthru");
+    decryptHandle->decryptApiType = DecryptApiType::ELEMENTARY_STREAM_BASED;
+    decryptHandle->status = DRM_NO_ERROR;
+    decryptHandle->decryptInfo = NULL;
+    return DRM_NO_ERROR;
+#endif
+
+    return DRM_ERROR_CANNOT_HANDLE;
+}
+
+status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    LOGD("DrmPassthruPlugIn::onCloseDecryptSession() : %d", uniqueId);
+    if (NULL != decryptHandle) {
+        if (NULL != decryptHandle->decryptInfo) {
+            delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
+        }
+        delete decryptHandle; decryptHandle = NULL;
+    }
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    LOGD("DrmPassthruPlugIn::onInitializeDecryptUnit() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    LOGD("DrmPassthruPlugIn::onDecrypt() : %d", uniqueId);
+    /**
+     * As a workaround implementation passthru would copy the given
+     * encrypted buffer as it is to decrypted buffer. Note, decBuffer
+     * memory has to be allocated by the caller.
+     */
+    if (NULL != (*decBuffer) && 0 < (*decBuffer)->length) {
+        memcpy((*decBuffer)->data, encBuffer->data, encBuffer->length);
+        (*decBuffer)->length = encBuffer->length;
+    }
+    return DRM_NO_ERROR;
+}
+
+status_t DrmPassthruPlugIn::onFinalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    LOGD("DrmPassthruPlugIn::onFinalizeDecryptUnit() : %d", uniqueId);
+    return DRM_NO_ERROR;
+}
+
+ssize_t DrmPassthruPlugIn::onPread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off_t offset) {
+    LOGD("DrmPassthruPlugIn::onPread() : %d", uniqueId);
+    return 0;
+}
+
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 8ac2aa0..a587d0d1 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1221,7 +1221,7 @@
             checkRange(texs.length, texOffset, vertexCount);
         }
         if (colors != null) {
-            checkRange(colors.length, colorOffset, vertexCount);
+            checkRange(colors.length, colorOffset, vertexCount / 2);
         }
         if (indices != null) {
             checkRange(indices.length, indexOffset, indexCount);
diff --git a/include/drm/DrmConstraints.h b/include/drm/DrmConstraints.h
new file mode 100644
index 0000000..a9ec942
--- /dev/null
+++ b/include/drm/DrmConstraints.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_CONSTRAINTS_H__
+#define __DRM_CONSTRAINTS_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class which contains the constraints information.
+ *
+ * As a result of DrmManagerClient::getConstraints(const String8*, const int)
+ * an instance of DrmConstraints would be returned.
+ *
+ */
+class DrmConstraints {
+public:
+    /**
+     * The following variables are replica of android.drm.DrmStore.ConstraintsColumns
+     * Any changes should also be incorporated with Java Layer as well
+     */
+    /**
+     * The max repeat count
+     */
+    static const String8 MAX_REPEAT_COUNT;
+    /**
+     * The remaining repeat count
+     */
+    static const String8 REMAINING_REPEAT_COUNT;
+
+    /**
+     * The time before which the protected file can not be played/viewed
+     */
+    static const String8 LICENSE_START_TIME;
+
+    /**
+     * The time after which the protected file can not be played/viewed
+     */
+    static const String8 LICENSE_EXPIRY_TIME;
+
+    /**
+     * The available time for license
+     */
+    static const String8 LICENSE_AVAILABLE_TIME;
+
+    /**
+     * The data stream for extended metadata
+     */
+    static const String8 EXTENDED_METADATA;
+
+public:
+    /**
+     * Iterator for key
+     */
+    class KeyIterator {
+        friend class DrmConstraints;
+    private:
+        KeyIterator(DrmConstraints* drmConstraints)
+            : mDrmConstraints(drmConstraints), mIndex(0) {}
+
+    public:
+        KeyIterator(const KeyIterator& keyIterator);
+        KeyIterator& operator=(const KeyIterator& keyIterator);
+        virtual ~KeyIterator() {}
+
+    public:
+        bool hasNext();
+        const String8& next();
+
+    private:
+        DrmConstraints* mDrmConstraints;
+        unsigned int mIndex;
+    };
+
+    /**
+     * Iterator for constraints
+     */
+    class Iterator {
+        friend class DrmConstraints;
+    private:
+        Iterator(DrmConstraints* drmConstraints)
+            : mDrmConstraints(drmConstraints), mIndex(0) {}
+
+    public:
+        Iterator(const Iterator& iterator);
+        Iterator& operator=(const Iterator& iterator);
+        virtual ~Iterator() {}
+
+    public:
+        bool hasNext();
+        String8 next();
+
+    private:
+        DrmConstraints* mDrmConstraints;
+        unsigned int mIndex;
+    };
+
+public:
+    DrmConstraints() {}
+    virtual ~DrmConstraints() {
+        DrmConstraints::KeyIterator keyIt = this->keyIterator();
+
+        while (keyIt.hasNext()) {
+            String8 key = keyIt.next();
+                const char* value = this->getAsByteArray(&key);
+                if (NULL != value) {
+                    delete[] value;
+                    value = NULL;
+                }
+        }
+        mConstraintMap.clear();
+    }
+public:
+    /**
+     * Returns the number of constraints contained in this instance
+     *
+     * @return Number of constraints
+     */
+    int getCount(void) const;
+
+    /**
+     * Adds constraint information as <key, value> pair to this instance
+     *
+     * @param[in] key Key to add
+     * @param[in] value Value to add
+     * @return Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t put(const String8* key, const char* value);
+
+    /**
+     * Retrieves the value of given key
+     *
+     * @param key Key whose value to be retrieved
+     * @return The value
+     */
+    String8 get(const String8& key) const;
+
+     /**
+     * Retrieves the value as byte array of given key
+     * @param key Key whose value to be retrieved as byte array
+     * @return The byte array value
+     */
+    const char* getAsByteArray(const String8* key) const;
+
+    /**
+     * Returns KeyIterator object to walk through the keys associated with this instance
+     *
+     * @return KeyIterator object
+     */
+    KeyIterator keyIterator();
+
+    /**
+     * Returns Iterator object to walk through the values associated with this instance
+     *
+     * @return Iterator object
+     */
+    Iterator iterator();
+private:
+    const char* getValue(const String8* key) const;
+private:
+    typedef KeyedVector<String8, const char*> DrmConstraintsMap;
+    DrmConstraintsMap mConstraintMap;
+};
+
+};
+
+#endif /* __DRM_CONSTRAINTS_H__ */
+
diff --git a/include/drm/DrmConvertedStatus.h b/include/drm/DrmConvertedStatus.h
new file mode 100644
index 0000000..679e48d
--- /dev/null
+++ b/include/drm/DrmConvertedStatus.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_CONVERTED_STATUS_H__
+#define __DRM_CONVERTED_STATUS_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class which wraps the status of the conversion, the converted
+ * data/checksum data and the offset. Offset is going to be used in the case of close
+ * session where the agent will inform where the header and body signature should be added
+ *
+ * As a result of DrmManagerClient::convertData(int, const DrmBuffer*) and
+ * DrmManagerClient::closeConvertSession(int) an instance of DrmConvertedStatus
+ * would be returned.
+ *
+ */
+class DrmConvertedStatus {
+public:
+    // Should be in sync with DrmConvertedStatus.java
+    static const int STATUS_OK = 1;
+    static const int STATUS_INPUTDATA_ERROR = 2;
+    static const int STATUS_ERROR = 3;
+
+public:
+    /**
+     * Constructor for DrmConvertedStatus
+     *
+     * @param[in] _statusCode Status of the conversion
+     * @param[in] _convertedData Converted data/checksum data
+     * @param[in] _offset Offset value
+     */
+    DrmConvertedStatus(int _statusCode, const DrmBuffer* _convertedData, int _offset);
+
+    /**
+     * Destructor for DrmConvertedStatus
+     */
+    virtual ~DrmConvertedStatus() {
+
+    }
+
+public:
+    int statusCode;
+    const DrmBuffer* convertedData;
+    int offset;
+};
+
+};
+
+#endif /* __DRM_CONVERTED_STATUS_H__ */
+
diff --git a/include/drm/DrmInfo.h b/include/drm/DrmInfo.h
new file mode 100644
index 0000000..7b48541
--- /dev/null
+++ b/include/drm/DrmInfo.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_INFO_H__
+#define __DRM_INFO_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class in which necessary information required to transact
+ * between device and online DRM server is described. DRM Framework achieves
+ * server registration, license acquisition and any other server related transaction
+ * by passing an instance of this class to DrmManagerClient::processDrmInfo(const DrmInfo*).
+ *
+ * The Caller can retrieve the DrmInfo instance by using
+ * DrmManagerClient::acquireDrmInfo(const DrmInfoRequest*) by passing DrmInfoRequest instance.
+ *
+ */
+class DrmInfo {
+public:
+    /**
+     * Constructor for DrmInfo
+     *
+     * @param[in] infoType Type of information
+     * @param[in] drmBuffer Trigger data
+     * @param[in] mimeType MIME type
+     */
+    DrmInfo(int infoType, const DrmBuffer& drmBuffer, const String8& mimeType);
+
+    /**
+     * Destructor for DrmInfo
+     */
+    virtual ~DrmInfo() {}
+
+public:
+    /**
+     * Iterator for key
+     */
+    class KeyIterator {
+        friend class DrmInfo;
+
+    private:
+        KeyIterator(const DrmInfo* drmInfo)
+            : mDrmInfo(const_cast <DrmInfo*> (drmInfo)), mIndex(0) {}
+
+    public:
+        KeyIterator(const KeyIterator& keyIterator);
+        KeyIterator& operator=(const KeyIterator& keyIterator);
+        virtual ~KeyIterator() {}
+
+    public:
+        bool hasNext();
+        const String8& next();
+
+    private:
+        DrmInfo* mDrmInfo;
+        unsigned int mIndex;
+    };
+
+    /**
+     * Iterator
+     */
+    class Iterator {
+        friend class DrmInfo;
+
+    private:
+        Iterator(const DrmInfo* drmInfo)
+            : mDrmInfo(const_cast <DrmInfo*> (drmInfo)), mIndex(0) {}
+
+    public:
+        Iterator(const Iterator& iterator);
+        Iterator& operator=(const Iterator& iterator);
+        virtual ~Iterator() {}
+
+    public:
+        bool hasNext();
+        String8& next();
+
+    private:
+        DrmInfo* mDrmInfo;
+        unsigned int mIndex;
+    };
+
+public:
+    /**
+     * Returns information type associated with this instance
+     *
+     * @return Information type
+     */
+    int getInfoType(void) const;
+
+    /**
+     * Returns MIME type associated with this instance
+     *
+     * @return MIME type
+     */
+    String8 getMimeType(void) const;
+
+    /**
+     * Returns the trigger data associated with this instance
+     *
+     * @return Trigger data
+     */
+    const DrmBuffer& getData(void) const;
+
+    /**
+     * Returns the number of attributes contained in this instance
+     *
+     * @return Number of attributes
+     */
+    int getCount(void) const;
+
+    /**
+     * Adds optional information as <key, value> pair to this instance
+     *
+     * @param[in] key Key to add
+     * @param[in] value Value to add
+     * @return Returns the error code
+     */
+    status_t put(const String8& key, const String8& value);
+
+    /**
+     * Retrieves the value of given key
+     *
+     * @param key Key whose value to be retrieved
+     * @return The value
+     */
+    String8 get(const String8& key) const;
+
+    /**
+     * Returns KeyIterator object to walk through the keys associated with this instance
+     *
+     * @return KeyIterator object
+     */
+    KeyIterator keyIterator() const;
+
+    /**
+     * Returns Iterator object to walk through the values associated with this instance
+     *
+     * @return Iterator object
+     */
+    Iterator iterator() const;
+
+    /**
+     * Returns index of the given key
+     *
+     * @return index
+     */
+    int indexOfKey(const String8& key) const;
+
+protected:
+    int mInfoType;
+    DrmBuffer mData;
+    String8 mMimeType;
+    KeyedVector<String8, String8> mAttributes;
+};
+
+};
+
+#endif /* __DRM_INFO_H__ */
+
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
new file mode 100644
index 0000000..c722bd3
--- /dev/null
+++ b/include/drm/DrmInfoEvent.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_INFO_EVENT_H__
+#define __DRM_INFO_EVENT_H__
+
+namespace android {
+
+class String8;
+
+/**
+ * This is an entity class which would be passed to caller in
+ * DrmManagerClient::OnInfoListener::onInfo(const DrmInfoEvent&).
+ */
+class DrmInfoEvent {
+public:
+    /**
+     * The following constant values should be in sync with DrmInfoEvent.java
+     */
+    //! TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been
+    //! already done by another account ID.
+    static const int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1;
+    //! TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
+    static const int TYPE_REMOVE_RIGHTS = 2;
+    //! TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
+    static const int TYPE_RIGHTS_INSTALLED = 3;
+    //! TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone,
+    //! wait before calling checkRights again
+    static const int TYPE_WAIT_FOR_RIGHTS = 4;
+    //! TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
+    //! already done for the given account.
+    static const int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+
+    /**
+     * The following constant values should be in sync with DrmErrorEvent.java
+     */
+    //! TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights
+    static const int TYPE_RIGHTS_NOT_INSTALLED = 2001;
+    //! TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights
+    static const int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002;
+    //! TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent
+    static const int TYPE_NOT_SUPPORTED = 2003;
+    //! TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
+    //! Can in the future perhaps be used to trigger garbage collector
+    static const int TYPE_OUT_OF_MEMORY = 2004;
+    //! TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
+    //! can be made to renew rights
+    static const int TYPE_NO_INTERNET_CONNECTION = 2005;
+    //! TYPE_REGISTRATION_FAILED, when registration with server failed.
+    static const int TYPE_REGISTRATION_FAILED = 2006;
+
+public:
+    /**
+     * Constructor for DrmInfoEvent
+     *
+     * @param[in] uniqueId Unique session identifier
+     * @param[in] infoType Type of information
+     * @param[in] message Message description
+     */
+    DrmInfoEvent(int uniqueId, int infoType, const String8& message);
+
+    /**
+     * Destructor for DrmInfoEvent
+     */
+    virtual ~DrmInfoEvent() {}
+
+public:
+    /**
+     * Returns the Unique Id associated with this instance
+     *
+     * @return Unique Id
+     */
+    int getUniqueId() const;
+
+    /**
+     * Returns the Type of information associated with this object
+     *
+     * @return Type of information
+     */
+    int getType() const;
+
+    /**
+     * Returns the message description associated with this object
+     *
+     * @return Message description
+     */
+    const String8& getMessage() const;
+
+private:
+    int mUniqueId;
+    int mInfoType;
+    const String8& mMessage;
+};
+
+};
+
+#endif /* __DRM_INFO_EVENT_H__ */
+
diff --git a/include/drm/DrmInfoRequest.h b/include/drm/DrmInfoRequest.h
new file mode 100644
index 0000000..3e48ecc
--- /dev/null
+++ b/include/drm/DrmInfoRequest.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_INFO_REQUEST_H__
+#define __DRM_INFO_REQUEST_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class used to pass required parameters to get
+ * the necessary information to communicate with online DRM server
+ *
+ * An instance of this class is passed to
+ * DrmManagerClient::acquireDrmInfo(const DrmInfoRequest*) to get the
+ * instance of DrmInfo.
+ *
+ */
+class DrmInfoRequest {
+public:
+    // Changes in following constants should be in sync with DrmInfoRequest.java
+    static const int TYPE_REGISTRATION_INFO = 1;
+    static const int TYPE_UNREGISTRATION_INFO = 2;
+    static const int TYPE_RIGHTS_ACQUISITION_INFO = 3;
+    static const int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4;
+
+    /**
+     * Key to pass the unique id for the account or the user
+     */
+    static const String8 ACCOUNT_ID;
+    /**
+     * Key to pass the subscription id
+     */
+    static const String8 SUBSCRIPTION_ID;
+
+public:
+    /**
+     * Constructor for DrmInfoRequest
+     *
+     * @param[in] infoType Type of information
+     * @param[in] mimeType MIME type
+     */
+    DrmInfoRequest(int infoType, const String8& mimeType);
+
+    /**
+     * Destructor for DrmInfoRequest
+     */
+    virtual ~DrmInfoRequest() {}
+
+public:
+    /**
+     * Iterator for key
+     */
+    class KeyIterator {
+        friend class DrmInfoRequest;
+
+    private:
+        KeyIterator(const DrmInfoRequest* drmInfoRequest)
+            : mDrmInfoRequest(const_cast <DrmInfoRequest*> (drmInfoRequest)), mIndex(0) {}
+
+    public:
+        KeyIterator(const KeyIterator& keyIterator);
+        KeyIterator& operator=(const KeyIterator& keyIterator);
+        virtual ~KeyIterator() {}
+
+    public:
+        bool hasNext();
+        const String8& next();
+
+    private:
+        DrmInfoRequest* mDrmInfoRequest;
+        unsigned int mIndex;
+    };
+
+    /**
+     * Iterator
+     */
+    class Iterator {
+        friend class DrmInfoRequest;
+
+    private:
+        Iterator(const DrmInfoRequest* drmInfoRequest)
+            : mDrmInfoRequest(const_cast <DrmInfoRequest*> (drmInfoRequest)), mIndex(0) {}
+
+    public:
+        Iterator(const Iterator& iterator);
+        Iterator& operator=(const Iterator& iterator);
+        virtual ~Iterator() {}
+
+    public:
+        bool hasNext();
+        String8& next();
+
+    private:
+        DrmInfoRequest* mDrmInfoRequest;
+        unsigned int mIndex;
+    };
+
+public:
+    /**
+     * Returns information type associated with this instance
+     *
+     * @return Information type
+     */
+    int getInfoType(void) const;
+
+    /**
+     * Returns MIME type associated with this instance
+     *
+     * @return MIME type
+     */
+    String8 getMimeType(void) const;
+
+    /**
+     * Returns the number of entries in DrmRequestInfoMap
+     *
+     * @return Number of entries
+     */
+    int getCount(void) const;
+
+    /**
+     * Adds optional information as <key, value> pair to this instance
+     *
+     * @param[in] key Key to add
+     * @param[in] value Value to add
+     * @return Returns the error code
+     */
+    status_t put(const String8& key, const String8& value);
+
+    /**
+     * Retrieves the value of given key
+     *
+     * @param key Key whose value to be retrieved
+     * @return The value
+     */
+    String8 get(const String8& key) const;
+
+    /**
+     * Returns KeyIterator object to walk through the keys associated with this instance
+     *
+     * @return KeyIterator object
+     */
+    KeyIterator keyIterator() const;
+
+    /**
+     * Returns Iterator object to walk through the values associated with this instance
+     *
+     * @return Iterator object
+     */
+    Iterator iterator() const;
+
+private:
+    int mInfoType;
+    String8 mMimeType;
+
+    typedef KeyedVector<String8, String8> DrmRequestInfoMap;
+    DrmRequestInfoMap mRequestInformationMap;
+};
+
+};
+
+#endif /* __DRM_INFO_REQUEST_H__ */
+
diff --git a/include/drm/DrmInfoStatus.h b/include/drm/DrmInfoStatus.h
new file mode 100644
index 0000000..806aea1
--- /dev/null
+++ b/include/drm/DrmInfoStatus.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_INFO_STATUS_H__
+#define __DRM_INFO_STATUS_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class which wraps the result of communication between device
+ * and online DRM server.
+ *
+ * As a result of DrmManagerClient::processDrmInfo(const DrmInfo*) an instance of
+ * DrmInfoStatus would be returned. This class holds DrmBuffer which could be
+ * used to instantiate DrmRights in license acquisition.
+ *
+ */
+class DrmInfoStatus {
+public:
+    // Should be in sync with DrmInfoStatus.java
+    static const int STATUS_OK = 1;
+    static const int STATUS_ERROR = 2;
+
+public:
+    /**
+     * Constructor for DrmInfoStatus
+     *
+     * @param[in] _statusCode Status of the communication
+     * @param[in] _drmBuffer Rights information
+     * @param[in] _mimeType MIME type
+     */
+    DrmInfoStatus(int _statusCode, const DrmBuffer* _drmBuffer, const String8& _mimeType);
+
+    /**
+     * Destructor for DrmInfoStatus
+     */
+    virtual ~DrmInfoStatus() {
+
+    }
+
+public:
+    int statusCode;
+    const DrmBuffer* drmBuffer;
+    String8 mimeType;
+};
+
+};
+
+#endif /* __DRM_INFO_STATUS_H__ */
+
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
new file mode 100644
index 0000000..c2ad084
--- /dev/null
+++ b/include/drm/DrmManagerClient.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_MANAGER_CLIENT_H__
+#define __DRM_MANAGER_CLIENT_H__
+
+#include <binder/IInterface.h>
+#include "drm_framework_common.h"
+
+namespace android {
+
+class DrmInfo;
+class DrmRights;
+class DrmInfoEvent;
+class DrmInfoStatus;
+class DrmInfoRequest;
+class DrmSupportInfo;
+class DrmConstraints;
+class DrmConvertedStatus;
+class DrmManagerClientImpl;
+
+/**
+ * The Native application will instantiate this class and access DRM Framework
+ * services through this class.
+ *
+ */
+class DrmManagerClient {
+public:
+    DrmManagerClient();
+
+    virtual ~DrmManagerClient();
+
+public:
+    class OnInfoListener: virtual public RefBase {
+
+    public:
+        virtual void onInfo(const DrmInfoEvent& event) = 0;
+    };
+
+/**
+ * APIs which will be used by native modules (e.g. StageFright)
+ *
+ */
+public:
+    /**
+     * Open the decrypt session to decrypt the given protected content
+     *
+     * @param[in] fd File descriptor of the protected content to be decrypted
+     * @param[in] offset Start position of the content
+     * @param[in] length The length of the protected content
+     * @return
+     *     Handle for the decryption session
+     */
+    DecryptHandle* openDecryptSession(int fd, int offset, int length);
+
+    /**
+     * Close the decrypt session for the given handle
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t closeDecryptSession(DecryptHandle* decryptHandle);
+
+    /**
+     * Consumes the rights for a content.
+     * If the reserve parameter is true the rights is reserved until the same
+     * application calls this api again with the reserve parameter set to false.
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
+     * @param[in] reserve True if the rights should be reserved.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure.
+     *     In case license has been expired, DRM_ERROR_LICENSE_EXPIRED will be returned.
+     */
+    status_t consumeRights(DecryptHandle* decryptHandle, int action, bool reserve);
+
+    /**
+     * Informs the DRM engine about the playback actions performed on the DRM files.
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
+     * @param[in] position Position in the file (in milliseconds) where the start occurs.
+     *                     Only valid together with Playback::START.
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t setPlaybackStatus(DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    /**
+     * Initialize decryption for the given unit of the protected content
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @param[in] headerInfo Information for initializing decryption of this decrypUnit
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t initializeDecryptUnit(
+            DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo);
+
+    /**
+     * Decrypt the protected content buffers for the given unit
+     * This method will be called any number of times, based on number of
+     * encrypted streams received from application.
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @param[in] encBuffer Encrypted data block
+     * @param[out] decBuffer Decrypted data block
+     * @param[in] IV Optional buffer
+     * @return status_t
+     *     Returns the error code for this API
+     *     DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
+     *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
+     *     DRM_ERROR_DECRYPT for failure.
+     */
+    status_t decrypt(
+            DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV = NULL);
+
+    /**
+     * Finalize decryption for the given unit of the protected content
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId);
+
+    /**
+     * Reads the specified number of bytes from an open DRM file.
+     *
+     * @param[in] decryptHandle Handle for the decryption session
+     * @param[out] buffer Reference to the buffer that should receive the read data.
+     * @param[in] numBytes Number of bytes to read.
+     * @param[in] offset Offset with which to update the file position.
+     *
+     * @return Number of bytes read. Returns -1 for Failure.
+     */
+    ssize_t pread(DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off_t offset);
+
+    /**
+     * Validates whether an action on the DRM content is allowed or not.
+     *
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to validate. (Action::DEFAULT, Action::PLAY, etc)
+     * @param[in] description Detailed description of the action
+     * @return true if the action is allowed.
+     */
+    bool validateAction(const String8& path, int action, const ActionDescription& description);
+
+/**
+ * APIs which are just the underlying implementation for the Java API
+ *
+ */
+public:
+    /**
+     * Register a callback to be invoked when the caller required to
+     * receive necessary information
+     *
+     * @param[in] infoListener Listener
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t setOnInfoListener(const sp<DrmManagerClient::OnInfoListener>& infoListener);
+
+    /**
+     * Get constraint information associated with input content
+     *
+     * @param[in] path Path of the protected content
+     * @param[in] action Actions defined such as,
+     *             Action::DEFAULT, Action::PLAY, etc
+     * @return DrmConstraints
+     *     key-value pairs of constraint are embedded in it
+     * @note
+     *     In case of error, return NULL
+     */
+    DrmConstraints* getConstraints(const String8* path, const int action);
+
+    /**
+     * Check whether the given mimetype or path can be handled
+     *
+     * @param[in] path Path of the content needs to be handled
+     * @param[in] mimetype Mimetype of the content needs to be handled
+     * @return
+     *     True if DrmManager can handle given path or mime type.
+     */
+    bool canHandle(const String8& path, const String8& mimeType);
+
+    /**
+     * Executes given drm information based on its type
+     *
+     * @param[in] drmInfo Information needs to be processed
+     * @return DrmInfoStatus
+     *     instance as a result of processing given input
+     */
+    DrmInfoStatus* processDrmInfo(const DrmInfo* drmInfo);
+
+    /**
+     * Retrieves necessary information for registration, unregistration or rights
+     * acquisition information.
+     *
+     * @param[in] drmInfoRequest Request information to retrieve drmInfo
+     * @return DrmInfo
+     *     instance as a result of processing given input
+     */
+    DrmInfo* acquireDrmInfo(const DrmInfoRequest* drmInfoRequest);
+
+    /**
+     * Save DRM rights to specified rights path
+     * and make association with content path
+     *
+     * @param[in] drmRights DrmRights to be saved
+     * @param[in] rightsPath File path where rights to be saved
+     * @param[in] contentPath File path where content was saved
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t saveRights(
+        const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath);
+
+    /**
+     * Retrieves the mime type embedded inside the original content
+     *
+     * @param[in] path the path of the protected content
+     * @return String8
+     *     Returns mime-type of the original content, such as "video/mpeg"
+     */
+    String8 getOriginalMimeType(const String8& path);
+
+    /**
+     * Retrieves the type of the protected object (content, rights, etc..)
+     * by using specified path or mimetype. At least one parameter should be non null
+     * to retrieve DRM object type
+     *
+     * @param[in] path Path of the content or null.
+     * @param[in] mimeType Mime type of the content or null.
+     * @return type of the DRM content,
+     *     such as DrmObjectType::CONTENT, DrmObjectType::RIGHTS_OBJECT
+     */
+    int getDrmObjectType(const String8& path, const String8& mimeType);
+
+    /**
+     * Check whether the given content has valid rights or not
+     *
+     * @param[in] path Path of the protected content
+     * @param[in] action Action to perform
+     * @return the status of the rights for the protected content,
+     *     such as RightsStatus::RIGHTS_VALID, RightsStatus::RIGHTS_EXPIRED, etc.
+     */
+    int checkRightsStatus(const String8& path, int action);
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param[in] path Path of the protected content
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t removeRights(const String8& path);
+
+    /**
+     * Removes all the rights information of each plug-in associated with
+     * DRM framework. Will be used in master reset
+     *
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t removeAllRights();
+
+    /**
+     * This API is for Forward Lock DRM.
+     * Each time the application tries to download a new DRM file
+     * which needs to be converted, then the application has to
+     * begin with calling this API.
+     *
+     * @param[in] convertId Handle for the convert session
+     * @param[in] mimeType Description/MIME type of the input data packet
+     * @return Return handle for the convert session
+     */
+    int openConvertSession(const String8& mimeType);
+
+    /**
+     * Passes the input data which need to be converted. The resultant
+     * converted data and the status is returned in the DrmConvertedInfo
+     * object. This method will be called each time there are new block
+     * of data received by the application.
+     *
+     * @param[in] convertId Handle for the convert session
+     * @param[in] inputData Input Data which need to be converted
+     * @return Return object contains the status of the data conversion,
+     *     the output converted data and offset. In this case the
+     *     application will ignore the offset information.
+     */
+    DrmConvertedStatus* convertData(int convertId, const DrmBuffer* inputData);
+
+    /**
+     * When there is no more data which need to be converted or when an
+     * error occurs that time the application has to inform the Drm agent
+     * via this API. Upon successful conversion of the complete data,
+     * the agent will inform that where the header and body signature
+     * should be added. This signature appending is needed to integrity
+     * protect the converted file.
+     *
+     * @param[in] convertId Handle for the convert session
+     * @return Return object contains the status of the data conversion,
+     *     the header and body signature data. It also informs
+     *     the application on which offset these signature data
+     *     should be appended.
+     */
+    DrmConvertedStatus* closeConvertSession(int convertId);
+
+    /**
+     * Retrieves all DrmSupportInfo instance that native DRM framework can handle.
+     * This interface is meant to be used by JNI layer
+     *
+     * @param[out] length Number of elements in drmSupportInfoArray
+     * @param[out] drmSupportInfoArray Array contains all DrmSupportInfo
+     *     that native DRM framework can handle
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t getAllSupportInfo(int* length, DrmSupportInfo** drmSupportInfoArray);
+
+private:
+    /**
+     * Initialize DRM Manager
+     *     load available plug-ins from default plugInDirPath
+     *
+     * @return status_t
+     *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t loadPlugIns();
+
+    /**
+     * Finalize DRM Manager
+     *    release resources associated with each plug-in
+     *    unload all plug-ins and etc.
+     *
+     * @return status_t
+     *    Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t unloadPlugIns();
+
+private:
+    int mUniqueId;
+    DrmManagerClientImpl* mDrmManagerClientImpl;
+};
+
+};
+
+#endif /* __DRM_MANAGER_CLIENT_H__ */
+
diff --git a/include/drm/DrmRights.h b/include/drm/DrmRights.h
new file mode 100644
index 0000000..11f8f78
--- /dev/null
+++ b/include/drm/DrmRights.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_RIGHTS_H__
+#define __DRM_RIGHTS_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class which wraps the license information which was
+ * retrieved from the online DRM server.
+ *
+ * Caller can instantiate DrmRights by invoking DrmRights(const DrmBuffer&, String)
+ * constructor by using the result of DrmManagerClient::ProcessDrmInfo(const DrmInfo*) API.
+ * Caller can also instantiate DrmRights using the file path which contains rights information.
+ *
+ */
+class DrmRights {
+public:
+    /**
+     * Constructor for DrmRights
+     *
+     * @param[in] rightsFilePath Path of the file containing rights data
+     * @param[in] mimeType MIME type
+     * @param[in] accountId Account Id of the user
+     * @param[in] subscriptionId Subscription Id of the user
+     */
+    DrmRights(
+            const String8& rightsFilePath, const String8& mimeType,
+            const String8& accountId = String8("_NO_USER"),
+            const String8& subscriptionId = String8(""));
+
+    /**
+     * Constructor for DrmRights
+     *
+     * @param[in] rightsData Rights data
+     * @param[in] mimeType MIME type
+     * @param[in] accountId Account Id of the user
+     * @param[in] subscriptionId Subscription Id of the user
+     */
+    DrmRights(
+            const DrmBuffer& rightsData, const String8& mimeType,
+            const String8& accountId = String8("_NO_USER"),
+            const String8& subscriptionId = String8(""));
+
+    /**
+     * Destructor for DrmRights
+     */
+    virtual ~DrmRights();
+
+public:
+    /**
+     * Returns the rights data associated with this instance
+     *
+     * @return Rights data
+     */
+    const DrmBuffer& getData(void) const;
+
+    /**
+     * Returns MIME type associated with this instance
+     *
+     * @return MIME type
+     */
+    String8 getMimeType(void) const;
+
+    /**
+     * Returns the account-id associated with this instance
+     *
+     * @return Account Id
+     */
+    String8 getAccountId(void) const;
+
+    /**
+     * Returns the subscription-id associated with this object
+     *
+     * @return Subscription Id
+     */
+    String8 getSubscriptionId(void) const;
+
+private:
+    DrmBuffer mData;
+    String8 mMimeType;
+    String8 mAccountId;
+    String8 mSubscriptionId;
+    char* mRightsFromFile;
+};
+
+};
+
+#endif /* __DRM_RIGHTS_H__ */
+
diff --git a/include/drm/DrmSupportInfo.h b/include/drm/DrmSupportInfo.h
new file mode 100644
index 0000000..bf12b0b
--- /dev/null
+++ b/include/drm/DrmSupportInfo.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_SUPPORT_INFO_H__
+#define __DRM_SUPPORT_INFO_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class which wraps the capability of each plug-in,
+ * such as mimetype's and file suffixes it could handle.
+ *
+ * Plug-in developer could return the capability of the plugin by passing
+ * DrmSupportInfo instance.
+ *
+ */
+class DrmSupportInfo {
+public:
+    /**
+     * Iterator for mMimeTypeVector
+     */
+    class MimeTypeIterator {
+        friend class DrmSupportInfo;
+    private:
+        MimeTypeIterator(DrmSupportInfo* drmSupportInfo)
+           : mDrmSupportInfo(drmSupportInfo), mIndex(0) {}
+    public:
+        MimeTypeIterator(const MimeTypeIterator& iterator);
+        MimeTypeIterator& operator=(const MimeTypeIterator& iterator);
+        virtual ~MimeTypeIterator() {}
+
+    public:
+        bool hasNext();
+        String8& next();
+
+    private:
+        DrmSupportInfo* mDrmSupportInfo;
+        unsigned int mIndex;
+    };
+
+    /**
+     * Iterator for mFileSuffixVector
+     */
+    class FileSuffixIterator {
+       friend class DrmSupportInfo;
+
+    private:
+        FileSuffixIterator(DrmSupportInfo* drmSupportInfo)
+            : mDrmSupportInfo(drmSupportInfo), mIndex(0) {}
+    public:
+        FileSuffixIterator(const FileSuffixIterator& iterator);
+        FileSuffixIterator& operator=(const FileSuffixIterator& iterator);
+        virtual ~FileSuffixIterator() {}
+
+    public:
+        bool hasNext();
+        String8& next();
+
+    private:
+        DrmSupportInfo* mDrmSupportInfo;
+        unsigned int mIndex;
+    };
+
+public:
+    /**
+     * Constructor for DrmSupportInfo
+     */
+    DrmSupportInfo();
+
+    /**
+     * Copy constructor for DrmSupportInfo
+     */
+    DrmSupportInfo(const DrmSupportInfo& drmSupportInfo);
+
+    /**
+     * Destructor for DrmSupportInfo
+     */
+    virtual ~DrmSupportInfo() {}
+
+    DrmSupportInfo& operator=(const DrmSupportInfo& drmSupportInfo);
+    bool operator<(const DrmSupportInfo& drmSupportInfo) const;
+    bool operator==(const DrmSupportInfo& drmSupportInfo) const;
+
+    /**
+     * Returns FileSuffixIterator object to walk through file suffix values
+     * associated with this instance
+     *
+     * @return FileSuffixIterator object
+     */
+    FileSuffixIterator getFileSuffixIterator();
+
+    /**
+     * Returns MimeTypeIterator object to walk through mimetype values
+     * associated with this instance
+     *
+     * @return MimeTypeIterator object
+     */
+    MimeTypeIterator getMimeTypeIterator();
+
+public:
+    /**
+     * Returns the number of mimetypes supported.
+     *
+     * @return Number of mimetypes supported
+     */
+    int getMimeTypeCount(void) const;
+
+    /**
+     * Returns the number of file types supported.
+     *
+     * @return Number of file types supported
+     */
+    int getFileSuffixCount(void) const;
+
+    /**
+     * Adds the mimetype to the list of supported mimetypes
+     *
+     * @param[in] mimeType mimetype to be added
+     * @return Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t addMimeType(const String8& mimeType);
+
+    /**
+     * Adds the filesuffix to the list of supported file types
+     *
+     * @param[in] filesuffix file suffix to be added
+     * @return Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t addFileSuffix(const String8& fileSuffix);
+
+    /**
+     * Set the unique description about the plugin
+     *
+     * @param[in] description Unique description
+     * @return Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+     */
+    status_t setDescription(const String8& description);
+
+    /**
+     * Returns the unique description associated with the plugin
+     *
+     * @return Unique description
+     */
+    String8 getDescription() const;
+
+    /**
+     * Returns whether given mimetype is supported or not
+     *
+     * @param[in] mimeType MIME type
+     * @return
+     *        true - if mime-type is supported
+     *        false - if mime-type is not supported
+     */
+    bool isSupportedMimeType(const String8& mimeType) const;
+
+    /**
+     * Returns whether given file type is supported or not
+     *
+     * @param[in] fileType File type
+     * @return
+     *     true if file type is supported
+     *     false if file type is not supported
+     */
+    bool isSupportedFileSuffix(const String8& fileType) const;
+
+private:
+    Vector<String8> mMimeTypeVector;
+    Vector<String8> mFileSuffixVector;
+
+    String8 mDescription;
+};
+
+};
+
+#endif /* __DRM_SUPPORT_INFO_H__ */
+
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
new file mode 100644
index 0000000..c5765a9
--- /dev/null
+++ b/include/drm/drm_framework_common.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_FRAMEWORK_COMMON_H__
+#define __DRM_FRAMEWORK_COMMON_H__
+
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+
+#define INVALID_VALUE -1
+
+namespace android {
+
+/**
+ * Error code for DRM Frameowrk
+ */
+enum {
+    DRM_ERROR_BASE = -2000,
+
+    DRM_ERROR_UNKNOWN                       = DRM_ERROR_BASE,
+    DRM_ERROR_LICENSE_EXPIRED               = DRM_ERROR_BASE - 1,
+    DRM_ERROR_SESSION_NOT_OPENED            = DRM_ERROR_BASE - 2,
+    DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED  = DRM_ERROR_BASE - 3,
+    DRM_ERROR_DECRYPT                       = DRM_ERROR_BASE - 4,
+    DRM_ERROR_CANNOT_HANDLE                 = DRM_ERROR_BASE - 5,
+
+    DRM_NO_ERROR                            = NO_ERROR
+};
+
+/**
+ * Defines DRM Buffer
+ */
+class DrmBuffer {
+public:
+    char* data;
+    int length;
+
+    DrmBuffer() :
+        data(NULL),
+        length(0) {
+    }
+
+    DrmBuffer(char* dataBytes, int dataLength) :
+        data(dataBytes),
+        length(dataLength) {
+    }
+
+};
+
+/**
+ * Defines detailed description of the action
+ */
+class ActionDescription {
+public:
+    ActionDescription(int _outputType, int _configuration) :
+        outputType(_outputType),
+        configuration(_configuration) {
+    }
+
+public:
+    int outputType;   /* BLUETOOTH , HDMI*/
+    int configuration; /* RESOLUTION_720_480 , RECORDABLE etc.*/
+};
+
+/**
+ * Defines constants related to DRM types
+ */
+class DrmObjectType {
+private:
+    DrmObjectType();
+
+public:
+    /**
+     * Field specifies the unknown type
+     */
+    static const int UNKNOWN = 0x00;
+    /**
+     * Field specifies the protected content type
+     */
+    static const int CONTENT = 0x01;
+    /**
+     * Field specifies the rights information
+     */
+    static const int RIGHTS_OBJECT = 0x02;
+    /**
+     * Field specifies the trigger information
+     */
+    static const int TRIGGER_OBJECT = 0x03;
+};
+
+/**
+ * Defines constants related to play back
+ */
+class Playback {
+private:
+    Playback();
+
+public:
+    /**
+     * Constant field signifies playback start
+     */
+    static const int START = 0x00;
+    /**
+     * Constant field signifies playback stop
+     */
+    static const int STOP = 0x01;
+    /**
+     * Constant field signifies playback paused
+     */
+    static const int PAUSE = 0x02;
+    /**
+     * Constant field signifies playback resumed
+     */
+    static const int RESUME = 0x03;
+};
+
+/**
+ * Defines actions that can be performed on protected content
+ */
+class Action {
+private:
+    Action();
+
+public:
+    /**
+     * Constant field signifies that the default action
+     */
+    static const int DEFAULT = 0x00;
+    /**
+     * Constant field signifies that the content can be played
+     */
+    static const int PLAY = 0x01;
+    /**
+     * Constant field signifies that the content can be set as ring tone
+     */
+    static const int RINGTONE = 0x02;
+    /**
+     * Constant field signifies that the content can be transfered
+     */
+    static const int TRANSFER = 0x03;
+    /**
+     * Constant field signifies that the content can be set as output
+     */
+    static const int OUTPUT = 0x04;
+    /**
+     * Constant field signifies that preview is allowed
+     */
+    static const int PREVIEW = 0x05;
+    /**
+     * Constant field signifies that the content can be executed
+     */
+    static const int EXECUTE = 0x06;
+    /**
+     * Constant field signifies that the content can displayed
+     */
+    static const int DISPLAY = 0x07;
+};
+
+/**
+ * Defines constants related to status of the rights
+ */
+class RightsStatus {
+private:
+    RightsStatus();
+
+public:
+    /**
+     * Constant field signifies that the rights are valid
+     */
+    static const int RIGHTS_VALID = 0x00;
+    /**
+     * Constant field signifies that the rights are invalid
+     */
+    static const int RIGHTS_INVALID = 0x01;
+    /**
+     * Constant field signifies that the rights are expired for the content
+     */
+    static const int RIGHTS_EXPIRED = 0x02;
+    /**
+     * Constant field signifies that the rights are not acquired for the content
+     */
+    static const int RIGHTS_NOT_ACQUIRED = 0x03;
+};
+
+/**
+ * Defines API set for decryption
+ */
+class DecryptApiType {
+private:
+    DecryptApiType();
+
+public:
+    /**
+     * Decrypt API set for non encrypted content
+     */
+    static const int NON_ENCRYPTED = 0x00;
+    /**
+     * Decrypt API set for ES based DRM
+     */
+    static const int ELEMENTARY_STREAM_BASED = 0x01;
+    /**
+     * POSIX based Decrypt API set for container based DRM
+     */
+    static const int CONTAINER_BASED = 0x02;
+};
+
+/**
+ * Defines decryption information
+ */
+class DecryptInfo {
+public:
+    /**
+     * size of memory to be allocated to get the decrypted content.
+     */
+    int decryptBufferLength;
+    /**
+     * reserved for future purpose
+     */
+};
+
+/**
+ * Defines decryption handle
+ */
+class DecryptHandle {
+public:
+    /**
+     * Decryption session Handle
+     */
+    int decryptId;
+    /**
+     * Mimetype of the content to be used to select the media extractor
+     * For e.g., "video/mpeg" or "audio/mp3"
+     */
+    String8 mimeType;
+    /**
+     * Defines which decryption pattern should be used to decrypt the given content
+     * DrmFramework provides two different set of decryption APIs.
+     *   1. Decrypt APIs for elementary stream based DRM
+     *      (file format is not encrypted but ES is encrypted)
+     *         e.g., Marlin DRM (MP4 file format), WM-DRM (asf file format)
+     *
+     *         DecryptApiType::ELEMENTARY_STREAM_BASED
+     *             Decryption API set for ES based DRM
+     *                 initializeDecryptUnit(), decrypt(), and finalizeDecryptUnit()
+     *   2. Decrypt APIs for container based DRM (file format itself is encrypted)
+     *         e.g., OMA DRM (dcf file format)
+     *
+     *         DecryptApiType::CONTAINER_BASED
+     *             POSIX based Decryption API set for container based DRM
+     *                 pread()
+     */
+    int decryptApiType;
+    /**
+     * Defines the status of the rights like
+     *     RIGHTS_VALID, RIGHTS_INVALID, RIGHTS_EXPIRED or RIGHTS_NOT_ACQUIRED
+     */
+    int status;
+    /**
+     * Information required to decrypt content
+     * e.g. size of memory to be allocated to get the decrypted content.
+     */
+    DecryptInfo* decryptInfo;
+
+public:
+    DecryptHandle():
+            decryptId(INVALID_VALUE),
+            mimeType(""),
+            decryptApiType(INVALID_VALUE),
+            status(INVALID_VALUE) {
+
+    }
+
+    bool operator<(const DecryptHandle& handle) const {
+        return (decryptId < handle.decryptId);
+    }
+
+    bool operator==(const DecryptHandle& handle) const {
+        return (decryptId == handle.decryptId);
+    }
+};
+
+};
+
+#endif /* __DRM_FRAMEWORK_COMMON_H__ */
+
diff --git a/libs/rs/rsNoise.cpp b/libs/rs/rsNoise.cpp
index 764dc1a..4b67586 100644
--- a/libs/rs/rsNoise.cpp
+++ b/libs/rs/rsNoise.cpp
@@ -253,4 +253,4 @@
 }
 
 }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 013f8fc..3333268 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1215,8 +1215,12 @@
             prescan(path);
 
             File file = new File(path);
+
+            // lastModified is in milliseconds on Files.
+            long lastModifiedSeconds = file.lastModified() / 1000;
+
             // always scan the file, so we can return the content://media Uri for existing files
-            return mClient.doScanFile(path, mimeType, file.lastModified(), file.length(), true);
+            return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(), true);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
             return null;
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 6f581d3..c5112a5 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -81,13 +81,13 @@
 }
 
 static bool fileMatchesExtension(const char* path, const char* extensions) {
-    char* extension = strrchr(path, '.');
+    const char* extension = strrchr(path, '.');
     if (!extension) return false;
     ++extension;    // skip the dot
     if (extension[0] == 0) return false;
 
     while (extensions[0]) {
-        char* comma = strchr(extensions, ',');
+        const char* comma = strchr(extensions, ',');
         size_t length = (comma ? comma - extensions : strlen(extensions));
         if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true;
         extensions += length;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index ba33e17..1555801 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -480,13 +480,13 @@
     copybit_device_t* const copybit = blitengine;
     if (copybit)  {
         copybit_image_t simg;
-        simg.w = src->width;
+        simg.w = src->stride;
         simg.h = src->height;
         simg.format = src->format;
         simg.handle = const_cast<native_handle_t*>(src->handle);
 
         copybit_image_t dimg;
-        dimg.w = dst->width;
+        dimg.w = dst->stride;
         dimg.h = dst->height;
         dimg.format = dst->format;
         dimg.handle = const_cast<native_handle_t*>(dst->handle);
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index f031c79..ef66841 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -181,4 +181,3 @@
 {
     background = 1.0f - background;
 }
-
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 4e2f1e3..4931cc7 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -124,6 +124,14 @@
     public AlarmManagerService(Context context) {
         mContext = context;
         mDescriptor = init();
+
+        // We have to set current TimeZone info to kernel
+        // because kernel doesn't keep this after reboot
+        String tz = SystemProperties.get(TIMEZONE_PROPERTY);
+        if (tz != null) {
+            setTimeZone(tz);
+        }
+
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index a663c3a..7c9b547 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -27,6 +27,7 @@
 import android.net.MobileDataStateTracker;
 import android.net.NetworkInfo;
 import android.net.NetworkStateTracker;
+import android.net.NetworkUtils;
 import android.net.wifi.WifiStateTracker;
 import android.os.Binder;
 import android.os.Handler;
@@ -50,6 +51,8 @@
 import java.util.ArrayList;
 import java.util.GregorianCalendar;
 import java.util.List;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 
 /**
  * @hide
@@ -805,6 +808,8 @@
     }
 
     /**
+     * @deprecated use requestRouteToHostAddress instead
+     *
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the specified network interface.
      * @param networkType the type of the network over which traffic to the
@@ -814,6 +819,25 @@
      * @return {@code true} on success, {@code false} on failure
      */
     public boolean requestRouteToHost(int networkType, int hostAddress) {
+        InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
+
+        if (inetAddress == null) {
+            return false;
+        }
+
+        return requestRouteToHostAddress(networkType, inetAddress.getAddress());
+    }
+
+    /**
+     * Ensure that a network route exists to deliver traffic to the specified
+     * host via the specified network interface.
+     * @param networkType the type of the network over which traffic to the
+     * specified host is to be routed
+     * @param hostAddress the IP address of the host to which the route is
+     * desired
+     * @return {@code true} on success, {@code false} on failure
+     */
+    public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
         enforceChangePermission();
         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
             return false;
@@ -823,11 +847,18 @@
         if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
                 tracker.isTeardownRequested()) {
             if (DBG) {
-                Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped");
+                Slog.d(TAG, "requestRouteToHostAddress on down network " +
+                           "(" + networkType + ") - dropped");
             }
             return false;
         }
-        return tracker.requestRouteToHost(hostAddress);
+
+        try {
+            InetAddress inetAddress = InetAddress.getByAddress(hostAddress);
+            return tracker.requestRouteToHost(inetAddress);
+        } catch (UnknownHostException e) {
+            return false;
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index e8c1613..4da5eb2 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -133,11 +133,11 @@
     private boolean mBatteryFull;
     private NotificationRecord mLedNotification;
 
-    private static final int BATTERY_LOW_ARGB = 0xFFFF0000; // Charging Low - red solid on
-    private static final int BATTERY_MEDIUM_ARGB = 0xFFFFFF00;    // Charging - orange solid on
-    private static final int BATTERY_FULL_ARGB = 0xFF00FF00; // Charging Full - green solid on
-    private static final int BATTERY_BLINK_ON = 125;
-    private static final int BATTERY_BLINK_OFF = 2875;
+    private static int mBatteryLowARGB;
+    private static int mBatteryMediumARGB;
+    private static int mBatteryFullARGB;
+    private static int mBatteryLedOn;
+    private static int mBatteryLedOff;
 
     private static String idDebugString(Context baseContext, String packageName, int id) {
         Context c = null;
@@ -452,6 +452,17 @@
         mDefaultNotificationLedOff = resources.getInteger(
                 com.android.internal.R.integer.config_defaultNotificationLedOff);
 
+        mBatteryLowARGB = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_notificationsBatteryLowARGB);
+        mBatteryMediumARGB = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
+        mBatteryFullARGB = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_notificationsBatteryFullARGB);
+        mBatteryLedOn = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_notificationsBatteryLedOn);
+        mBatteryLedOff = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_notificationsBatteryLedOff);
+
         // Don't start allowing notifications until the setup wizard has run once.
         // After that, including subsequent boots, init with notifications turned on.
         // This works on the first boot because the setup wizard will toggle this
@@ -1067,17 +1078,17 @@
         // Battery low always shows, other states only show if charging.
         if (mBatteryLow) {
             if (mBatteryCharging) {
-                mBatteryLight.setColor(BATTERY_LOW_ARGB);
+                mBatteryLight.setColor(mBatteryLowARGB);
             } else {
                 // Flash when battery is low and not charging
-                mBatteryLight.setFlashing(BATTERY_LOW_ARGB, LightsService.LIGHT_FLASH_TIMED,
-                        BATTERY_BLINK_ON, BATTERY_BLINK_OFF);
+                mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
+                        mBatteryLedOn, mBatteryLedOff);
             }
         } else if (mBatteryCharging) {
             if (mBatteryFull) {
-                mBatteryLight.setColor(BATTERY_FULL_ARGB);
+                mBatteryLight.setColor(mBatteryFullARGB);
             } else {
-                mBatteryLight.setColor(BATTERY_MEDIUM_ARGB);
+                mBatteryLight.setColor(mBatteryMediumARGB);
             }
         } else {
             mBatteryLight.turnOff();
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index 020f9ed..43dbcc0 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -811,7 +811,7 @@
                         break;
                     }
                 }
-                return new String(mBuffer, 0, 0, i);
+                return new String(mBuffer, 0, i);
             }
         } catch (java.io.FileNotFoundException e) {
         } catch (java.io.IOException e) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 1b2ddcc..9ca53c6 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -1482,6 +1482,7 @@
                 WindowState wb = localmWindows.get(foundI-1);
                 if (wb.mBaseLayer < maxLayer &&
                         wb.mAttachedWindow != foundW &&
+                        wb.mAttachedWindow != foundW.mAttachedWindow &&
                         (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
                                 wb.mToken != foundW.mToken)) {
                     // This window is not related to the previous one in any
@@ -7591,7 +7592,8 @@
                 WindowState win = allAppWindows.get(i);
                 if (win == startingWindow || win.mAppFreezing
                         || win.mViewVisibility != View.VISIBLE
-                        || win.mAttrs.type == TYPE_APPLICATION_STARTING) {
+                        || win.mAttrs.type == TYPE_APPLICATION_STARTING
+                        || win.mDestroying) {
                     continue;
                 }
                 if (DEBUG_VISIBILITY) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6db4559..6a05d3c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -55,6 +55,7 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IIntentReceiver;
@@ -1116,7 +1117,7 @@
                 d.setCancelable(false);
                 d.setTitle("System UIDs Inconsistent");
                 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
-                d.setButton("I'm Feeling Lucky",
+                d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
                         mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
                 mUidAlert = d;
                 d.show();
@@ -3678,10 +3679,12 @@
                 String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                 if (pkgs != null) {
                     for (String pkg : pkgs) {
-                        if (forceStopPackageLocked(pkg, -1, false, false, false)) {
-                            setResultCode(Activity.RESULT_OK);
-                            return;
-                        }
+                        synchronized (ActivityManagerService.this) {
+                          if (forceStopPackageLocked(pkg, -1, false, false, false)) {
+                              setResultCode(Activity.RESULT_OK);
+                              return;
+                          }
+                       }
                     }
                 }
             }
@@ -6435,7 +6438,28 @@
                 sr.crashCount++;
             }
         }
-        
+
+        // If the crashing process is what we consider to be the "home process" and it has been
+        // replaced by a third-party app, clear the package preferred activities from packages
+        // with a home activity running in the process to prevent a repeatedly crashing app
+        // from blocking the user to manually clear the list.
+        if (app == mHomeProcess && mHomeProcess.activities.size() > 0
+                    && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            Iterator it = mHomeProcess.activities.iterator();
+            while (it.hasNext()) {
+                ActivityRecord r = (ActivityRecord)it.next();
+                if (r.isHomeActivity) {
+                    Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
+                    try {
+                        ActivityThread.getPackageManager()
+                                .clearPackagePreferredActivities(r.packageName);
+                    } catch (RemoteException c) {
+                        // pm is in same process, this will never happen.
+                    }
+                }
+            }
+        }
+
         mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
         return true;
     }
@@ -6789,6 +6813,9 @@
             sb.append("Subject: ").append(subject).append("\n");
         }
         sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+        if (Debug.isDebuggerConnected()) {
+            sb.append("Debugger: Connected\n");
+        }
         sb.append("\n");
 
         // Do the rest in a worker thread to avoid blocking the caller on I/O
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 8e9818d..9fb48b3 100644
--- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.content.Context;
+import android.content.DialogInterface;
 import android.os.Handler;
 import android.os.Message;
 
@@ -49,7 +50,7 @@
         text.append(" is waiting for the debugger to attach.");
 
         setMessage(text.toString());
-        setButton("Force Close", mHandler.obtainMessage(1, app));
+        setButton(DialogInterface.BUTTON_POSITIVE, "Force Close", mHandler.obtainMessage(1, app));
         setTitle("Waiting For Debugger");
         getWindow().setTitle("Waiting For Debugger: " + app.info.processName);
     }
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java
index 2e25474..b19bb5ca 100644
--- a/services/java/com/android/server/am/FactoryErrorDialog.java
+++ b/services/java/com/android/server/am/FactoryErrorDialog.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.content.Context;
+import android.content.DialogInterface;
 import android.os.Handler;
 import android.os.Message;
 
@@ -26,7 +27,8 @@
         setCancelable(false);
         setTitle(context.getText(com.android.internal.R.string.factorytest_failed));
         setMessage(msg);
-        setButton(context.getText(com.android.internal.R.string.factorytest_reboot),
+        setButton(DialogInterface.BUTTON_POSITIVE,
+                context.getText(com.android.internal.R.string.factorytest_reboot),
                 mHandler.obtainMessage(0));
         getWindow().setTitle("Factory Error");
     }
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 8e7cadc..d4513e9 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -67,6 +67,7 @@
     jint healthDead;
     jint healthOverVoltage;
     jint healthUnspecifiedFailure;
+    jint healthCold;
 };
 static BatteryManagerConstants gConstants;
 
@@ -104,6 +105,7 @@
 static jint getBatteryHealth(const char* status)
 {
     switch (status[0]) {
+        case 'C': return gConstants.healthCold;         // Cold
         case 'D': return gConstants.healthDead;         // Dead
         case 'G': return gConstants.healthGood;         // Good
         case 'O': {
@@ -162,7 +164,7 @@
     
     jboolean value = false;
     if (readFromFile(path, buf, SIZE) > 0) {
-        if (buf[0] == '1') {
+        if (buf[0] != '0') {
             value = true;
         }
     }
@@ -390,6 +392,9 @@
     gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz, 
             env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
     
+    gConstants.healthCold = env->GetStaticIntField(clazz,
+            env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I"));
+
     return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
 }
 
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index 87cabed..c060895 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -501,7 +501,7 @@
     const ISurface::BufferHeap& buffers(mBufferHeap);
     uint32_t w = mLayer.mTransformedBounds.width();
     uint32_t h = mLayer.mTransformedBounds.height();
-    if (buffers.w * h != buffers.h * w) {
+    if (mLayer.getOrientation() & (Transform::ROT_90 | Transform::ROT_270)) {
         int t = w; w = h; h = t;
     }
 
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 5542c42..8e4f6fc 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -55,6 +55,12 @@
     public static final char WILD = 'N';
 
     /*
+     * Calling Line Identification Restriction (CLIR)
+     */
+    private static final String CLIR_ON = "*31#+";
+    private static final String CLIR_OFF = "#31#+";
+
+    /*
      * TOA = TON + NPI
      * See TS 24.008 section 10.5.4.7 for details.
      * These are the only really useful TOA values
@@ -179,8 +185,6 @@
      *  Please note that the GSM wild character is allowed in the result.
      *  This must be resolved before dialing.
      *
-     *  Allows + only in the first  position in the result string.
-     *
      *  Returns null if phoneNumber == null
      */
     public static String
@@ -203,6 +207,11 @@
             }
         }
 
+        int pos = addPlusChar(phoneNumber);
+        if (pos >= 0 && ret.length() > pos) {
+            ret.insert(pos, '+');
+        }
+
         return ret.toString();
     }
 
@@ -304,6 +313,28 @@
         }
     }
 
+    /** GSM codes
+     *  Finds if a GSM code includes the international prefix (+).
+     *
+     * @param number the number to dial.
+     *
+     * @return the position where the + char will be inserted, -1 if the GSM code was not found.
+     */
+    private static int
+    addPlusChar(String number) {
+        int pos = -1;
+
+        if (number.startsWith(CLIR_OFF)) {
+            pos = CLIR_OFF.length() - 1;
+        }
+
+        if (number.startsWith(CLIR_ON)) {
+            pos = CLIR_ON.length() - 1;
+        }
+
+        return pos;
+    }
+
     /**
      * Extracts the post-dial sequence of DTMF control digits, pauses, and
      * waits. Strips separators. This string may be empty, but will not be null
@@ -1119,7 +1150,7 @@
                 && text.charAt(2) == '1') {
                 formatType = FORMAT_JAPAN;
             } else {
-                return;
+                formatType = FORMAT_UNKNOWN;
             }
         }
 
@@ -1130,6 +1161,9 @@
             case FORMAT_JAPAN:
                 formatJapaneseNumber(text);
                 return;
+            case FORMAT_UNKNOWN:
+                removeDashes(text);
+                return;
         }
     }
 
@@ -1165,14 +1199,7 @@
         CharSequence saved = text.subSequence(0, length);
 
         // Strip the dashes first, as we're going to add them back
-        int p = 0;
-        while (p < text.length()) {
-            if (text.charAt(p) == '-') {
-                text.delete(p, p + 1);
-            } else {
-                p++;
-            }
-        }
+        removeDashes(text);
         length = text.length();
 
         // When scanning the number we record where dashes need to be added,
@@ -1276,6 +1303,22 @@
         JapanesePhoneNumberFormatter.format(text);
     }
 
+    /**
+     * Removes all dashes from the number.
+     *
+     * @param text the number to clear from dashes
+     */
+    private static void removeDashes(Editable text) {
+        int p = 0;
+        while (p < text.length()) {
+            if (text.charAt(p) == '-') {
+                text.delete(p, p + 1);
+           } else {
+                p++;
+           }
+        }
+    }
+
     // Three and four digit phone numbers for either special services,
     // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
     // not match.
diff --git a/telephony/java/com/android/internal/telephony/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
index c8c0658..a175d49 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecordCache.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
@@ -186,7 +186,12 @@
         }
 
         ArrayList<AdnRecord>  oldAdnList;
-        oldAdnList = getRecordsIfLoaded(efid);
+
+        if (efid == EF_PBR) {
+            oldAdnList = mUsimPhoneBookManager.loadEfFilesFromUsim();
+        } else {
+            oldAdnList = getRecordsIfLoaded(efid);
+        }
 
         if (oldAdnList == null) {
             sendErrorResponse(response, "Adn list not exist for EF:" + efid);
@@ -208,6 +213,17 @@
             return;
         }
 
+        if (efid == EF_PBR) {
+            AdnRecord foundAdn = oldAdnList.get(index-1);
+            efid = foundAdn.efid;
+            extensionEF = foundAdn.extRecord;
+            index = foundAdn.recordNumber;
+
+            newAdn.efid = efid;
+            newAdn.extRecord = extensionEF;
+            newAdn.recordNumber = index;
+        }
+
         Message pendingResponse = userWriteResponse.get(efid);
 
         if (pendingResponse != null) {
@@ -331,6 +347,7 @@
 
                 if (ar.exception == null) {
                     adnLikeFiles.get(efid).set(index - 1, adn);
+                    mUsimPhoneBookManager.invalidateCache();
                 }
 
                 Message response = userWriteResponse.get(efid);
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index b962375..815fbfb 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -73,10 +73,10 @@
     protected Registrant mSmsOnSimRegistrant;
     protected Registrant mSmsStatusRegistrant;
     protected Registrant mSsnRegistrant;
-    protected Registrant mStkSessionEndRegistrant;
-    protected Registrant mStkProCmdRegistrant;
-    protected Registrant mStkEventRegistrant;
-    protected Registrant mStkCallSetUpRegistrant;
+    protected Registrant mCatSessionEndRegistrant;
+    protected Registrant mCatProCmdRegistrant;
+    protected Registrant mCatEventRegistrant;
+    protected Registrant mCatCallSetUpRegistrant;
     protected Registrant mIccSmsFullRegistrant;
     protected Registrant mEmergencyCallbackModeRegistrant;
     protected Registrant mIccRefreshRegistrant;
@@ -395,36 +395,36 @@
         mSsnRegistrant.clear();
     }
 
-    public void setOnStkSessionEnd(Handler h, int what, Object obj) {
-        mStkSessionEndRegistrant = new Registrant (h, what, obj);
+    public void setOnCatSessionEnd(Handler h, int what, Object obj) {
+        mCatSessionEndRegistrant = new Registrant (h, what, obj);
     }
 
-    public void unSetOnStkSessionEnd(Handler h) {
-        mStkSessionEndRegistrant.clear();
+    public void unSetOnCatSessionEnd(Handler h) {
+        mCatSessionEndRegistrant.clear();
     }
 
-    public void setOnStkProactiveCmd(Handler h, int what, Object obj) {
-        mStkProCmdRegistrant = new Registrant (h, what, obj);
+    public void setOnCatProactiveCmd(Handler h, int what, Object obj) {
+        mCatProCmdRegistrant = new Registrant (h, what, obj);
     }
 
-    public void unSetOnStkProactiveCmd(Handler h) {
-        mStkProCmdRegistrant.clear();
+    public void unSetOnCatProactiveCmd(Handler h) {
+        mCatProCmdRegistrant.clear();
     }
 
-    public void setOnStkEvent(Handler h, int what, Object obj) {
-        mStkEventRegistrant = new Registrant (h, what, obj);
+    public void setOnCatEvent(Handler h, int what, Object obj) {
+        mCatEventRegistrant = new Registrant (h, what, obj);
     }
 
-    public void unSetOnStkEvent(Handler h) {
-        mStkEventRegistrant.clear();
+    public void unSetOnCatEvent(Handler h) {
+        mCatEventRegistrant.clear();
     }
 
-    public void setOnStkCallSetUp(Handler h, int what, Object obj) {
-        mStkCallSetUpRegistrant = new Registrant (h, what, obj);
+    public void setOnCatCallSetUp(Handler h, int what, Object obj) {
+        mCatCallSetUpRegistrant = new Registrant (h, what, obj);
     }
 
-    public void unSetOnStkCallSetUp(Handler h) {
-        mStkCallSetUpRegistrant.clear();
+    public void unSetOnCatCallSetUp(Handler h) {
+        mCatCallSetUpRegistrant.clear();
     }
 
     public void setOnIccSmsFull(Handler h, int what, Object obj) {
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 8e03c5a..5de0426 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -374,48 +374,48 @@
     void unSetOnSuppServiceNotification(Handler h);
 
     /**
-     * Sets the handler for Session End Notifications for STK.
+     * Sets the handler for Session End Notifications for CAT.
      * Unlike the register* methods, there's only one notification handler
      *
      * @param h Handler for notification message.
      * @param what User-defined message code.
      * @param obj User object.
      */
-    void setOnStkSessionEnd(Handler h, int what, Object obj);
-    void unSetOnStkSessionEnd(Handler h);
+    void setOnCatSessionEnd(Handler h, int what, Object obj);
+    void unSetOnCatSessionEnd(Handler h);
 
     /**
-     * Sets the handler for Proactive Commands for STK.
+     * Sets the handler for Proactive Commands for CAT.
      * Unlike the register* methods, there's only one notification handler
      *
      * @param h Handler for notification message.
      * @param what User-defined message code.
      * @param obj User object.
      */
-    void setOnStkProactiveCmd(Handler h, int what, Object obj);
-    void unSetOnStkProactiveCmd(Handler h);
+    void setOnCatProactiveCmd(Handler h, int what, Object obj);
+    void unSetOnCatProactiveCmd(Handler h);
 
     /**
-     * Sets the handler for Event Notifications for STK.
+     * Sets the handler for Event Notifications for CAT.
      * Unlike the register* methods, there's only one notification handler
      *
      * @param h Handler for notification message.
      * @param what User-defined message code.
      * @param obj User object.
      */
-    void setOnStkEvent(Handler h, int what, Object obj);
-    void unSetOnStkEvent(Handler h);
+    void setOnCatEvent(Handler h, int what, Object obj);
+    void unSetOnCatEvent(Handler h);
 
     /**
-     * Sets the handler for Call Set Up Notifications for STK.
+     * Sets the handler for Call Set Up Notifications for CAT.
      * Unlike the register* methods, there's only one notification handler
      *
      * @param h Handler for notification message.
      * @param what User-defined message code.
      * @param obj User object.
      */
-    void setOnStkCallSetUp(Handler h, int what, Object obj);
-    void unSetOnStkCallSetUp(Handler h);
+    void setOnCatCallSetUp(Handler h, int what, Object obj);
+    void unSetOnCatCallSetUp(Handler h);
 
     /**
      * Enables/disbables supplementary service related notifications from
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index d3a34ec..90f9e8c 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -672,12 +672,11 @@
      * @return true if a ICC card is present
      */
     public boolean hasIccCard() {
-        boolean isIccPresent;
-        if (mPhone.getPhoneName().equals("GSM")) {
-            return mIccCardStatus.getCardState().isCardPresent();
-        } else {
-            // TODO: Make work with a CDMA device with a RUIM card.
+        if (mIccCardStatus == null) {
             return false;
+        } else {
+            // Returns ICC card status for both GSM and CDMA mode
+            return mIccCardStatus.getCardState().isCardPresent();
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java
index acc9197..b12d2d4 100644
--- a/telephony/java/com/android/internal/telephony/IccConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccConstants.java
@@ -52,6 +52,7 @@
     static final int EF_SPN_CPHS = 0x6f14;
     static final int EF_SPN_SHORT_CPHS = 0x6f18;
     static final int EF_INFO_CPHS = 0x6f16;
+    static final int EF_CSP_CPHS = 0x6f15;
 
     // CDMA RUIM file ids from 3GPP2 C.S0023-0
     static final int EF_CST = 0x6f32;
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 9f8e57f..2f22d74 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -62,8 +62,8 @@
                             logd("GET_RECORD_SIZE Size " + recordSize[0] +
                                     " total " + recordSize[1] +
                                     " #record " + recordSize[2]);
-                            mLock.notifyAll();
                         }
+                        mLock.notifyAll();
                     }
                     break;
                 case EVENT_UPDATE_DONE:
@@ -144,6 +144,9 @@
         if (DBG) logd("updateAdnRecordsInEfBySearch: efid=" + efid +
                 " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" +
                 " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2);
+
+        efid = updateEfForIccType(efid);
+
         synchronized(mLock) {
             checkThread();
             success = false;
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 71936f1..957eddd 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -51,6 +51,8 @@
             ret.append((char)('0' + v));
 
             v = (data[i] >> 4) & 0xf;
+            // Some PLMNs have 'f' as high nibble, ignore it
+            if (v == 0xf) continue;
             if (v > 9)  break;
             ret.append((char)('0' + v));
         }
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index d5791eb..e426e94 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1715,4 +1715,15 @@
     void unsetOnEcbModeExitResponse(Handler h);
 
 
+    /**
+     * TODO: Adding a function for each property is not good.
+     * A fucntion of type getPhoneProp(propType) where propType is an
+     * enum of GSM+CDMA+LTE props would be a better approach.
+     *
+     * Get "Restriction of menu options for manual PLMN selection" bit
+     * status from EF_CSP data, this belongs to "Value Added Services Group".
+     * @return true if this bit is set or EF_CSP data is unavailable,
+     * false otherwise
+     */
+    boolean isCspPlmnEnabled();
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 53503a53..1674ad6 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -1022,6 +1022,13 @@
         }
     }
 
+    public boolean isCspPlmnEnabled() {
+        // This function should be overridden by the class GSMPhone.
+        // Not implemented in CDMAPhone.
+        logUnexpectedGsmMethodCall("isCspPlmnEnabled");
+        return false;
+    }
+
     /**
      * Common error logger method for unexpected calls to CDMA-only methods.
      */
@@ -1030,4 +1037,12 @@
         Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
                 "called, CDMAPhone inactive.");
     }
+
+    /**
+     * Common error logger method for unexpected calls to GSM/WCDMA-only methods.
+     */
+    private void logUnexpectedGsmMethodCall(String name) {
+        Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
+                "called, GSMPhone inactive.");
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 6f08868..77f1e6c 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -843,4 +843,8 @@
     public void unsetOnEcbModeExitResponse(Handler h){
         mActivePhone.unsetOnEcbModeExitResponse(h);
     }
+
+    public boolean isCspPlmnEnabled() {
+        return mActivePhone.isCspPlmnEnabled();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 3d410fd..a9a4be2 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1961,26 +1961,30 @@
         sendScreenState(true);
    }
 
-    private void setRadioStateFromRILInt(int state) {
-        RadioState newState;
+    private RadioState getRadioStateFromInt(int stateInt) {
+        RadioState state;
 
         /* RIL_RadioState ril.h */
-        switch(state) {
-            case 0: newState = RadioState.RADIO_OFF; break;
-            case 1: newState = RadioState.RADIO_UNAVAILABLE; break;
-            case 2: newState = RadioState.SIM_NOT_READY; break;
-            case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break;
-            case 4: newState = RadioState.SIM_READY; break;
-            case 5: newState = RadioState.RUIM_NOT_READY; break;
-            case 6: newState = RadioState.RUIM_READY; break;
-            case 7: newState = RadioState.RUIM_LOCKED_OR_ABSENT; break;
-            case 8: newState = RadioState.NV_NOT_READY; break;
-            case 9: newState = RadioState.NV_READY; break;
+        switch(stateInt) {
+            case 0: state = RadioState.RADIO_OFF; break;
+            case 1: state = RadioState.RADIO_UNAVAILABLE; break;
+            case 2: state = RadioState.SIM_NOT_READY; break;
+            case 3: state = RadioState.SIM_LOCKED_OR_ABSENT; break;
+            case 4: state = RadioState.SIM_READY; break;
+            case 5: state = RadioState.RUIM_NOT_READY; break;
+            case 6: state = RadioState.RUIM_READY; break;
+            case 7: state = RadioState.RUIM_LOCKED_OR_ABSENT; break;
+            case 8: state = RadioState.NV_NOT_READY; break;
+            case 9: state = RadioState.NV_READY; break;
 
             default:
                 throw new RuntimeException(
-                            "Unrecognized RIL_RadioState: " +state);
+                            "Unrecognized RIL_RadioState: " + stateInt);
         }
+        return state;
+    }
+
+    private void switchToRadioState(RadioState newState) {
 
         if (mInitialRadioStateChange) {
             if (newState.isOn()) {
@@ -2339,7 +2343,7 @@
             case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
             case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:  ret =  responseVoid(p); break;
             case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:  ret =  responseCdmaSms(p); break;
-            case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:  ret =  responseString(p); break;
+            case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:  ret =  responseRaw(p); break;
             case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:  ret =  responseVoid(p); break;
             case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break;
             case RIL_UNSOL_CDMA_CALL_WAITING: ret = responseCdmaCallWaiting(p); break;
@@ -2361,9 +2365,10 @@
         switch(response) {
             case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
                 /* has bonus radio state int */
-                setRadioStateFromRILInt(p.readInt());
+                RadioState newState = getRadioStateFromInt(p.readInt());
+                if (RILJ_LOGD) unsljLogMore(response, newState.toString());
 
-                if (RILJ_LOGD) unsljLogMore(response, mState.toString());
+                switchToRadioState(newState);
             break;
             case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
                 if (RILJ_LOGD) unsljLog(response);
@@ -2481,8 +2486,8 @@
             case RIL_UNSOL_STK_SESSION_END:
                 if (RILJ_LOGD) unsljLog(response);
 
-                if (mStkSessionEndRegistrant != null) {
-                    mStkSessionEndRegistrant.notifyRegistrant(
+                if (mCatSessionEndRegistrant != null) {
+                    mCatSessionEndRegistrant.notifyRegistrant(
                                         new AsyncResult (null, ret, null));
                 }
                 break;
@@ -2490,8 +2495,8 @@
             case RIL_UNSOL_STK_PROACTIVE_COMMAND:
                 if (RILJ_LOGD) unsljLogRet(response, ret);
 
-                if (mStkProCmdRegistrant != null) {
-                    mStkProCmdRegistrant.notifyRegistrant(
+                if (mCatProCmdRegistrant != null) {
+                    mCatProCmdRegistrant.notifyRegistrant(
                                         new AsyncResult (null, ret, null));
                 }
                 break;
@@ -2499,8 +2504,8 @@
             case RIL_UNSOL_STK_EVENT_NOTIFY:
                 if (RILJ_LOGD) unsljLogRet(response, ret);
 
-                if (mStkEventRegistrant != null) {
-                    mStkEventRegistrant.notifyRegistrant(
+                if (mCatEventRegistrant != null) {
+                    mCatEventRegistrant.notifyRegistrant(
                                         new AsyncResult (null, ret, null));
                 }
                 break;
@@ -2508,8 +2513,8 @@
             case RIL_UNSOL_STK_CALL_SETUP:
                 if (RILJ_LOGD) unsljLogRet(response, ret);
 
-                if (mStkCallSetUpRegistrant != null) {
-                    mStkCallSetUpRegistrant.notifyRegistrant(
+                if (mCatCallSetUpRegistrant != null) {
+                    mCatCallSetUpRegistrant.notifyRegistrant(
                                         new AsyncResult (null, ret, null));
                 }
                 break;
@@ -3406,6 +3411,8 @@
         RILRequest rr = RILRequest.obtain(
                 RILConstants.RIL_REQUEST_QUERY_TTY_MODE, response);
 
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
         send(rr);
     }
 
@@ -3419,6 +3426,9 @@
         rr.mp.writeInt(1);
         rr.mp.writeInt(ttyMode);
 
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                + " : " + ttyMode);
+
         send(rr);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index 168b63b..2f5d3ec 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -24,7 +24,6 @@
 import android.util.Config;
 import android.util.Log;
 
-
 /**
  * WAP push handler class.
  *
@@ -59,7 +58,7 @@
      */
     public int dispatchWapPdu(byte[] pdu) {
 
-        if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
+        if (Config.DEBUG) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
 
         int index = 0;
         int transactionId = pdu[index++] & 0xFF;
@@ -68,7 +67,7 @@
 
         if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
                 (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
-            if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
+            if (Config.DEBUG) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
             return Intents.RESULT_SMS_HANDLED;
         }
 
@@ -81,7 +80,7 @@
          * So it will be encoded in no more than 5 octets.
          */
         if (pduDecoder.decodeUintvarInteger(index) == false) {
-            if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error.");
+            if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Length error.");
             return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         headerLength = (int)pduDecoder.getValue32();
@@ -102,141 +101,44 @@
          * Length = Uintvar-integer
          */
         if (pduDecoder.decodeContentType(index) == false) {
-            if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
+            if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
             return Intents.RESULT_SMS_GENERIC_ERROR;
         }
-        int binaryContentType;
+
         String mimeType = pduDecoder.getValueString();
-        if (mimeType == null) {
-            binaryContentType = (int)pduDecoder.getValue32();
-            // TODO we should have more generic way to map binaryContentType code to mimeType.
-            switch (binaryContentType) {
-                case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_MMS:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_VND_DOCOMO_PF:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_VND_DOCOMO_PF;
-                    break;
-                case WspTypeDecoder.CONTENT_TYPE_B_SUPL_INIT:
-                    mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_SUPL_INIT;
-                    break;
-                default:
-                    if (Config.LOGD) {
-                        Log.w(LOG_TAG,
-                                "Received PDU. Unsupported Content-Type = " + binaryContentType);
-                    }
-                return Intents.RESULT_SMS_HANDLED;
-            }
-        } else {
-            if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_VND_DOCOMO_PF)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_VND_DOCOMO_PF;
-            } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_SUPL_INIT)) {
-                binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_SUPL_INIT;
-            } else {
-                if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
-                return Intents.RESULT_SMS_HANDLED;
-            }
-        }
+
         index += pduDecoder.getDecodedDataLength();
 
-        boolean dispatchedByApplication = false;
-        switch (binaryContentType) {
-            case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
-                dispatchWapPdu_PushCO(pdu, transactionId, pduType, headerStartIndex, headerLength);
-                dispatchedByApplication = true;
-                break;
-            case WspTypeDecoder.CONTENT_TYPE_B_MMS:
-                dispatchWapPdu_MMS(pdu, transactionId, pduType, headerStartIndex, headerLength);
-                dispatchedByApplication = true;
-                break;
-            default:
-                break;
-        }
-        if (dispatchedByApplication == false) {
-            dispatchWapPdu_default(pdu, transactionId, pduType, mimeType,
-                                   headerStartIndex, headerLength);
-        }
-        return Activity.RESULT_OK;
-    }
-
-    private void dispatchWapPdu_default(byte[] pdu, int transactionId, int pduType,
-                                        String mimeType, int headerStartIndex, int headerLength) {
         byte[] header = new byte[headerLength];
         System.arraycopy(pdu, headerStartIndex, header, 0, header.length);
-        int dataIndex = headerStartIndex + headerLength;
-        byte[] data;
 
-        data = new byte[pdu.length - dataIndex];
-        System.arraycopy(pdu, dataIndex, data, 0, data.length);
+        byte[] intentData;
+        String permission;
+
+        if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) {
+            intentData = pdu;
+        } else {
+            int dataIndex = headerStartIndex + headerLength;
+            intentData = new byte[pdu.length - dataIndex];
+            System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length);
+        }
+
+        if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_MMS)) {
+            permission = "android.permission.RECEIVE_MMS";
+        } else {
+            permission = "android.permission.RECEIVE_WAP_PUSH";
+        }
 
         Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
         intent.setType(mimeType);
         intent.putExtra("transactionId", transactionId);
         intent.putExtra("pduType", pduType);
         intent.putExtra("header", header);
-        intent.putExtra("data", data);
+        intent.putExtra("data", intentData);
+        intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());
 
-        mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH");
+        mSmsDispatcher.dispatch(intent, permission);
+
+        return Activity.RESULT_OK;
     }
-
-    private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType,
-                                       int headerStartIndex, int headerLength) {
-        byte[] header = new byte[headerLength];
-        System.arraycopy(pdu, headerStartIndex, header, 0, header.length);
-
-        Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
-        intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO);
-        intent.putExtra("transactionId", transactionId);
-        intent.putExtra("pduType", pduType);
-        intent.putExtra("header", header);
-        intent.putExtra("data", pdu);
-
-        mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH");
-    }
-
-    private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType,
-                                    int headerStartIndex, int headerLength) {
-        byte[] header = new byte[headerLength];
-        System.arraycopy(pdu, headerStartIndex, header, 0, header.length);
-        int dataIndex = headerStartIndex + headerLength;
-        byte[] data = new byte[pdu.length - dataIndex];
-        System.arraycopy(pdu, dataIndex, data, 0, data.length);
-
-        Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
-        intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS);
-        intent.putExtra("transactionId", transactionId);
-        intent.putExtra("pduType", pduType);
-        intent.putExtra("header", header);
-        intent.putExtra("data", data);
-
-        mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_MMS");
-    }
-}
-
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
index 5dc89f0..6bf6b13 100644
--- a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
+++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
@@ -16,11 +16,12 @@
 
 package com.android.internal.telephony;
 
+import java.util.HashMap;
 
 /**
- *  Implement the WSP data type decoder.
+ * Implement the WSP data type decoder.
  *
- *  @hide
+ * @hide
  */
 public class WspTypeDecoder {
 
@@ -30,37 +31,176 @@
     public static final int PDU_TYPE_PUSH = 0x06;
     public static final int PDU_TYPE_CONFIRMED_PUSH = 0x07;
 
-    // TODO we should have mapping between those binary code and mime type string.
-    //  see http://www.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx
+    private final static HashMap<Integer, String> WELL_KNOWN_MIME_TYPES =
+            new HashMap<Integer, String>();
 
-    public static final int CONTENT_TYPE_B_DRM_RIGHTS_XML = 0x4a;
-    public static final int CONTENT_TYPE_B_DRM_RIGHTS_WBXML = 0x4b;
-    public static final int CONTENT_TYPE_B_PUSH_SI = 0x2e;
-    public static final int CONTENT_TYPE_B_PUSH_SL = 0x30;
-    public static final int CONTENT_TYPE_B_PUSH_CO = 0x32;
-    public static final int CONTENT_TYPE_B_MMS = 0x3e;
-    public static final int CONTENT_TYPE_B_VND_DOCOMO_PF = 0x0310;
-    public static final int CONTENT_TYPE_B_SUPL_INIT = 0x312;
+    private final static HashMap<Integer, String> WELL_KNOWN_PARAMETERS =
+            new HashMap<Integer, String>();
 
-    public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML =
-            "application/vnd.oma.drm.rights+xml";
-    public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML =
-            "application/vnd.oma.drm.rights+wbxml";
-    public static final String CONTENT_MIME_TYPE_B_PUSH_SI = "application/vnd.wap.sic";
-    public static final String CONTENT_MIME_TYPE_B_PUSH_SL = "application/vnd.wap.slc";
-    public static final String CONTENT_MIME_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
-    public static final String CONTENT_MIME_TYPE_B_MMS = "application/vnd.wap.mms-message";
-    public static final String CONTENT_MIME_TYPE_B_VND_DOCOMO_PF = "application/vnd.docomo.pf";
-    public static final String CONTENT_MIME_TYPE_B_SUPL_INIT = "application/vnd.omaloc-supl-init";
+    private static final int Q_VALUE = 0x00;
 
-    public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f;
+    static {
+        WELL_KNOWN_MIME_TYPES.put(0x00, "*/*");
+        WELL_KNOWN_MIME_TYPES.put(0x01, "text/*");
+        WELL_KNOWN_MIME_TYPES.put(0x02, "text/html");
+        WELL_KNOWN_MIME_TYPES.put(0x03, "text/plain");
+        WELL_KNOWN_MIME_TYPES.put(0x04, "text/x-hdml");
+        WELL_KNOWN_MIME_TYPES.put(0x05, "text/x-ttml");
+        WELL_KNOWN_MIME_TYPES.put(0x06, "text/x-vCalendar");
+        WELL_KNOWN_MIME_TYPES.put(0x07, "text/x-vCard");
+        WELL_KNOWN_MIME_TYPES.put(0x08, "text/vnd.wap.wml");
+        WELL_KNOWN_MIME_TYPES.put(0x09, "text/vnd.wap.wmlscript");
+        WELL_KNOWN_MIME_TYPES.put(0x0A, "text/vnd.wap.wta-event");
+        WELL_KNOWN_MIME_TYPES.put(0x0B, "multipart/*");
+        WELL_KNOWN_MIME_TYPES.put(0x0C, "multipart/mixed");
+        WELL_KNOWN_MIME_TYPES.put(0x0D, "multipart/form-data");
+        WELL_KNOWN_MIME_TYPES.put(0x0E, "multipart/byterantes");
+        WELL_KNOWN_MIME_TYPES.put(0x0F, "multipart/alternative");
+        WELL_KNOWN_MIME_TYPES.put(0x10, "application/*");
+        WELL_KNOWN_MIME_TYPES.put(0x11, "application/java-vm");
+        WELL_KNOWN_MIME_TYPES.put(0x12, "application/x-www-form-urlencoded");
+        WELL_KNOWN_MIME_TYPES.put(0x13, "application/x-hdmlc");
+        WELL_KNOWN_MIME_TYPES.put(0x14, "application/vnd.wap.wmlc");
+        WELL_KNOWN_MIME_TYPES.put(0x15, "application/vnd.wap.wmlscriptc");
+        WELL_KNOWN_MIME_TYPES.put(0x16, "application/vnd.wap.wta-eventc");
+        WELL_KNOWN_MIME_TYPES.put(0x17, "application/vnd.wap.uaprof");
+        WELL_KNOWN_MIME_TYPES.put(0x18, "application/vnd.wap.wtls-ca-certificate");
+        WELL_KNOWN_MIME_TYPES.put(0x19, "application/vnd.wap.wtls-user-certificate");
+        WELL_KNOWN_MIME_TYPES.put(0x1A, "application/x-x509-ca-cert");
+        WELL_KNOWN_MIME_TYPES.put(0x1B, "application/x-x509-user-cert");
+        WELL_KNOWN_MIME_TYPES.put(0x1C, "image/*");
+        WELL_KNOWN_MIME_TYPES.put(0x1D, "image/gif");
+        WELL_KNOWN_MIME_TYPES.put(0x1E, "image/jpeg");
+        WELL_KNOWN_MIME_TYPES.put(0x1F, "image/tiff");
+        WELL_KNOWN_MIME_TYPES.put(0x20, "image/png");
+        WELL_KNOWN_MIME_TYPES.put(0x21, "image/vnd.wap.wbmp");
+        WELL_KNOWN_MIME_TYPES.put(0x22, "application/vnd.wap.multipart.*");
+        WELL_KNOWN_MIME_TYPES.put(0x23, "application/vnd.wap.multipart.mixed");
+        WELL_KNOWN_MIME_TYPES.put(0x24, "application/vnd.wap.multipart.form-data");
+        WELL_KNOWN_MIME_TYPES.put(0x25, "application/vnd.wap.multipart.byteranges");
+        WELL_KNOWN_MIME_TYPES.put(0x26, "application/vnd.wap.multipart.alternative");
+        WELL_KNOWN_MIME_TYPES.put(0x27, "application/xml");
+        WELL_KNOWN_MIME_TYPES.put(0x28, "text/xml");
+        WELL_KNOWN_MIME_TYPES.put(0x29, "application/vnd.wap.wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x2A, "application/x-x968-cross-cert");
+        WELL_KNOWN_MIME_TYPES.put(0x2B, "application/x-x968-ca-cert");
+        WELL_KNOWN_MIME_TYPES.put(0x2C, "application/x-x968-user-cert");
+        WELL_KNOWN_MIME_TYPES.put(0x2D, "text/vnd.wap.si");
+        WELL_KNOWN_MIME_TYPES.put(0x2E, "application/vnd.wap.sic");
+        WELL_KNOWN_MIME_TYPES.put(0x2F, "text/vnd.wap.sl");
+        WELL_KNOWN_MIME_TYPES.put(0x30, "application/vnd.wap.slc");
+        WELL_KNOWN_MIME_TYPES.put(0x31, "text/vnd.wap.co");
+        WELL_KNOWN_MIME_TYPES.put(0x32, "application/vnd.wap.coc");
+        WELL_KNOWN_MIME_TYPES.put(0x33, "application/vnd.wap.multipart.related");
+        WELL_KNOWN_MIME_TYPES.put(0x34, "application/vnd.wap.sia");
+        WELL_KNOWN_MIME_TYPES.put(0x35, "text/vnd.wap.connectivity-xml");
+        WELL_KNOWN_MIME_TYPES.put(0x36, "application/vnd.wap.connectivity-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x37, "application/pkcs7-mime");
+        WELL_KNOWN_MIME_TYPES.put(0x38, "application/vnd.wap.hashed-certificate");
+        WELL_KNOWN_MIME_TYPES.put(0x39, "application/vnd.wap.signed-certificate");
+        WELL_KNOWN_MIME_TYPES.put(0x3A, "application/vnd.wap.cert-response");
+        WELL_KNOWN_MIME_TYPES.put(0x3B, "application/xhtml+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x3C, "application/wml+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x3D, "text/css");
+        WELL_KNOWN_MIME_TYPES.put(0x3E, "application/vnd.wap.mms-message");
+        WELL_KNOWN_MIME_TYPES.put(0x3F, "application/vnd.wap.rollover-certificate");
+        WELL_KNOWN_MIME_TYPES.put(0x40, "application/vnd.wap.locc+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x41, "application/vnd.wap.loc+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x42, "application/vnd.syncml.dm+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x43, "application/vnd.syncml.dm+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x44, "application/vnd.syncml.notification");
+        WELL_KNOWN_MIME_TYPES.put(0x45, "application/vnd.wap.xhtml+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x46, "application/vnd.wv.csp.cir");
+        WELL_KNOWN_MIME_TYPES.put(0x47, "application/vnd.oma.dd+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x48, "application/vnd.oma.drm.message");
+        WELL_KNOWN_MIME_TYPES.put(0x49, "application/vnd.oma.drm.content");
+        WELL_KNOWN_MIME_TYPES.put(0x4A, "application/vnd.oma.drm.rights+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x4B, "application/vnd.oma.drm.rights+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x4C, "application/vnd.wv.csp+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x4D, "application/vnd.wv.csp+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x4E, "application/vnd.syncml.ds.notification");
+        WELL_KNOWN_MIME_TYPES.put(0x4F, "audio/*");
+        WELL_KNOWN_MIME_TYPES.put(0x50, "video/*");
+        WELL_KNOWN_MIME_TYPES.put(0x51, "application/vnd.oma.dd2+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x52, "application/mikey");
+        WELL_KNOWN_MIME_TYPES.put(0x53, "application/vnd.oma.dcd");
+        WELL_KNOWN_MIME_TYPES.put(0x54, "application/vnd.oma.dcdc");
 
+        WELL_KNOWN_MIME_TYPES.put(0x0201, "application/vnd.uplanet.cacheop-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0202, "application/vnd.uplanet.signal");
+        WELL_KNOWN_MIME_TYPES.put(0x0203, "application/vnd.uplanet.alert-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0204, "application/vnd.uplanet.list-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0205, "application/vnd.uplanet.listcmd-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0206, "application/vnd.uplanet.channel-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0207, "application/vnd.uplanet.provisioning-status-uri");
+        WELL_KNOWN_MIME_TYPES.put(0x0208, "x-wap.multipart/vnd.uplanet.header-set");
+        WELL_KNOWN_MIME_TYPES.put(0x0209, "application/vnd.uplanet.bearer-choice-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x020A, "application/vnd.phonecom.mmc-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x020B, "application/vnd.nokia.syncset+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x020C, "image/x-up-wpng");
+        WELL_KNOWN_MIME_TYPES.put(0x0300, "application/iota.mmc-wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0301, "application/iota.mmc-xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0302, "application/vnd.syncml+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0303, "application/vnd.syncml+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0304, "text/vnd.wap.emn+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0305, "text/calendar");
+        WELL_KNOWN_MIME_TYPES.put(0x0306, "application/vnd.omads-email+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0307, "application/vnd.omads-file+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0308, "application/vnd.omads-folder+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0309, "text/directory;profile=vCard");
+        WELL_KNOWN_MIME_TYPES.put(0x030A, "application/vnd.wap.emn+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x030B, "application/vnd.nokia.ipdc-purchase-response");
+        WELL_KNOWN_MIME_TYPES.put(0x030C, "application/vnd.motorola.screen3+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x030D, "application/vnd.motorola.screen3+gzip");
+        WELL_KNOWN_MIME_TYPES.put(0x030E, "application/vnd.cmcc.setting+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x030F, "application/vnd.cmcc.bombing+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0310, "application/vnd.docomo.pf");
+        WELL_KNOWN_MIME_TYPES.put(0x0311, "application/vnd.docomo.ub");
+        WELL_KNOWN_MIME_TYPES.put(0x0312, "application/vnd.omaloc-supl-init");
+        WELL_KNOWN_MIME_TYPES.put(0x0313, "application/vnd.oma.group-usage-list+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0314, "application/oma-directory+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x0315, "application/vnd.docomo.pf2");
+        WELL_KNOWN_MIME_TYPES.put(0x0316, "application/vnd.oma.drm.roap-trigger+wbxml");
+        WELL_KNOWN_MIME_TYPES.put(0x0317, "application/vnd.sbm.mid2");
+        WELL_KNOWN_MIME_TYPES.put(0x0318, "application/vnd.wmf.bootstrap");
+        WELL_KNOWN_MIME_TYPES.put(0x0319, "application/vnc.cmcc.dcd+xml");
+        WELL_KNOWN_MIME_TYPES.put(0x031A, "application/vnd.sbm.cid");
+        WELL_KNOWN_MIME_TYPES.put(0x031B, "application/vnd.oma.bcast.provisioningtrigger");
+
+        WELL_KNOWN_PARAMETERS.put(0x00, "Q");
+        WELL_KNOWN_PARAMETERS.put(0x01, "Charset");
+        WELL_KNOWN_PARAMETERS.put(0x02, "Level");
+        WELL_KNOWN_PARAMETERS.put(0x03, "Type");
+        WELL_KNOWN_PARAMETERS.put(0x07, "Differences");
+        WELL_KNOWN_PARAMETERS.put(0x08, "Padding");
+        WELL_KNOWN_PARAMETERS.put(0x09, "Type");
+        WELL_KNOWN_PARAMETERS.put(0x0E, "Max-Age");
+        WELL_KNOWN_PARAMETERS.put(0x10, "Secure");
+        WELL_KNOWN_PARAMETERS.put(0x11, "SEC");
+        WELL_KNOWN_PARAMETERS.put(0x12, "MAC");
+        WELL_KNOWN_PARAMETERS.put(0x13, "Creation-date");
+        WELL_KNOWN_PARAMETERS.put(0x14, "Modification-date");
+        WELL_KNOWN_PARAMETERS.put(0x15, "Read-date");
+        WELL_KNOWN_PARAMETERS.put(0x16, "Size");
+        WELL_KNOWN_PARAMETERS.put(0x17, "Name");
+        WELL_KNOWN_PARAMETERS.put(0x18, "Filename");
+        WELL_KNOWN_PARAMETERS.put(0x19, "Start");
+        WELL_KNOWN_PARAMETERS.put(0x1A, "Start-info");
+        WELL_KNOWN_PARAMETERS.put(0x1B, "Comment");
+        WELL_KNOWN_PARAMETERS.put(0x1C, "Domain");
+        WELL_KNOWN_PARAMETERS.put(0x1D, "Path");
+    }
+
+    public static final String CONTENT_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
+    public static final String CONTENT_TYPE_B_MMS = "application/vnd.wap.mms-message";
 
     byte[] wspData;
     int    dataLength;
     long   unsigned32bit;
     String stringValue;
 
+    HashMap<String, String> contentParameters;
+
     public WspTypeDecoder(byte[] pdu) {
         wspData = pdu;
     }
@@ -71,17 +211,17 @@
      * @param startIndex The starting position of the "Text-string" in this pdu
      *
      * @return false when error(not a Text-string) occur
-     *         return value can be retrieved by getValueString() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         return value can be retrieved by getValueString() method length of data in pdu can be
+     *         retrieved by getDecodedDataLength() method
      */
     public boolean decodeTextString(int startIndex) {
         int index = startIndex;
         while (wspData[index] != 0) {
             index++;
         }
-        dataLength  = index - startIndex + 1;
+        dataLength = index - startIndex + 1;
         if (wspData[startIndex] == 127) {
-            stringValue = new String(wspData, startIndex+1, dataLength - 2);
+            stringValue = new String(wspData, startIndex + 1, dataLength - 2);
         } else {
             stringValue = new String(wspData, startIndex, dataLength - 1);
         }
@@ -89,13 +229,33 @@
     }
 
     /**
+     * Decode the "Token-text" type for WSP pdu
+     *
+     * @param startIndex The starting position of the "Token-text" in this pdu
+     *
+     * @return always true
+     *         return value can be retrieved by getValueString() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
+     */
+    public boolean decodeTokenText(int startIndex) {
+        int index = startIndex;
+        while (wspData[index] != 0) {
+            index++;
+        }
+        dataLength = index - startIndex + 1;
+        stringValue = new String(wspData, startIndex, dataLength - 1);
+
+        return true;
+    }
+
+    /**
      * Decode the "Short-integer" type for WSP pdu
      *
      * @param startIndex The starting position of the "Short-integer" in this pdu
      *
      * @return false when error(not a Short-integer) occur
      *         return value can be retrieved by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeShortInteger(int startIndex) {
         if ((wspData[startIndex] & 0x80) == 0) {
@@ -113,7 +273,7 @@
      *
      * @return false when error(not a Long-integer) occur
      *         return value can be retrieved by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeLongInteger(int startIndex) {
         int lengthMultiOctet = wspData[startIndex] & 0xff;
@@ -122,10 +282,10 @@
             return false;
         }
         unsigned32bit = 0;
-        for (int i=1; i<=lengthMultiOctet; i++) {
-            unsigned32bit = (unsigned32bit << 8) | (wspData[startIndex+i] & 0xff);
+        for (int i = 1; i <= lengthMultiOctet; i++) {
+            unsigned32bit = (unsigned32bit << 8) | (wspData[startIndex + i] & 0xff);
         }
-        dataLength = 1+lengthMultiOctet;
+        dataLength = 1 + lengthMultiOctet;
         return true;
     }
 
@@ -136,7 +296,7 @@
      *
      * @return false when error(not a Integer-Value) occur
      *         return value can be retrieved by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeIntegerValue(int startIndex) {
         if (decodeShortInteger(startIndex) == true) {
@@ -152,10 +312,10 @@
      *
      * @return false when error(not a Uintvar-integer) occur
      *         return value can be retrieved by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeUintvarInteger(int startIndex) {
-        int  index = startIndex;
+        int index = startIndex;
 
         unsigned32bit = 0;
         while ((wspData[index] & 0x80) != 0) {
@@ -177,7 +337,7 @@
      *
      * @return false when error(not a Value-length) occur
      *         return value can be retrieved by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeValueLength(int startIndex) {
         if ((wspData[startIndex] & 0xff) > WAP_PDU_LENGTH_QUOTE) {
@@ -187,22 +347,22 @@
             unsigned32bit = wspData[startIndex];
             dataLength = 1;
         } else {
-            decodeUintvarInteger(startIndex+1);
-            dataLength ++;
+            decodeUintvarInteger(startIndex + 1);
+            dataLength++;
         }
         return true;
     }
 
     /**
-    * Decode the "Extension-media" type for WSP PDU.
-    *
-    * @param startIndex The starting position of the "Extension-media" in this PDU.
-    *
-    * @return false on error, such as if there is no Extension-media at startIndex.
-    * Side-effects: updates stringValue (available with getValueString()), which will be
-    * null on error. The length of the data in the PDU is available with getValue32(), 0
-    * on error.
-    */
+     * Decode the "Extension-media" type for WSP PDU.
+     *
+     * @param startIndex The starting position of the "Extension-media" in this PDU.
+     *
+     * @return false on error, such as if there is no Extension-media at startIndex.
+     *         Side-effects: updates stringValue (available with
+     *         getValueString()), which will be null on error. The length of the
+     *         data in the PDU is available with getValue32(), 0 on error.
+     */
     public boolean decodeExtensionMedia(int startIndex) {
         int index = startIndex;
         dataLength = 0;
@@ -214,7 +374,7 @@
             index++;
         }
 
-        dataLength  = index - startIndex + 1;
+        dataLength = index - startIndex + 1;
         stringValue = new String(wspData, startIndex, dataLength - 1);
 
         return rtrn;
@@ -227,7 +387,7 @@
      *
      * @return false when error(not a Constrained-encoding) occur
      *         return value can be retrieved first by getValueString() and second by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeConstrainedEncoding(int startIndex) {
         if (decodeShortInteger(startIndex) == true) {
@@ -242,31 +402,162 @@
      *
      * @param startIndex The starting position of the "Content-type" in this pdu
      *
-     * @return false when error(not a Content-type) occur
-     *         return value can be retrieved first by getValueString() and second by getValue32()
-     *         method length of data in pdu can be retrieved by getValue32() method
+     * @return false when error(not a Content-type) occurs
+     *         If a content type exists in the headers (either as inline string, or as well-known
+     *         value), getValueString() will return it. If a 'well known value' is encountered that
+     *         cannot be mapped to a string mime type, getValueString() will return null, and
+     *         getValue32() will return the unknown content type value.
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
+     *         Any content type parameters will be accessible via getContentParameters()
      */
     public boolean decodeContentType(int startIndex) {
         int mediaPrefixLength;
-        long mediaFieldLength;
+        contentParameters = new HashMap<String, String>();
 
-        if (decodeValueLength(startIndex) == false) {
-            return decodeConstrainedEncoding(startIndex);
-        }
-        mediaPrefixLength = getDecodedDataLength();
-        mediaFieldLength = getValue32();
-        if (decodeIntegerValue(startIndex + mediaPrefixLength) == true) {
-            dataLength += mediaPrefixLength;
-            stringValue = null;
-            return true;
-        }
-        if (decodeExtensionMedia(startIndex + mediaPrefixLength) == true) {
-            dataLength += mediaPrefixLength;
-            return true;
+        try {
+            if (decodeValueLength(startIndex) == false) {
+                boolean found = decodeConstrainedEncoding(startIndex);
+                if (found) {
+                    expandWellKnownMimeType();
+                }
+                return found;
+            }
+            int headersLength = (int) unsigned32bit;
+            mediaPrefixLength = getDecodedDataLength();
+            if (decodeIntegerValue(startIndex + mediaPrefixLength) == true) {
+                dataLength += mediaPrefixLength;
+                int readLength = dataLength;
+                stringValue = null;
+                expandWellKnownMimeType();
+                long wellKnownValue = unsigned32bit;
+                String mimeType = stringValue;
+                if (readContentParameters(startIndex + dataLength,
+                        (headersLength - (dataLength - mediaPrefixLength)), 0)) {
+                    dataLength += readLength;
+                    unsigned32bit = wellKnownValue;
+                    stringValue = mimeType;
+                    return true;
+                }
+                return false;
+            }
+            if (decodeExtensionMedia(startIndex + mediaPrefixLength) == true) {
+                dataLength += mediaPrefixLength;
+                int readLength = dataLength;
+                expandWellKnownMimeType();
+                long wellKnownValue = unsigned32bit;
+                String mimeType = stringValue;
+                if (readContentParameters(startIndex + dataLength,
+                        (headersLength - (dataLength - mediaPrefixLength)), 0)) {
+                    dataLength += readLength;
+                    unsigned32bit = wellKnownValue;
+                    stringValue = mimeType;
+                    return true;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            //something doesn't add up
+            return false;
         }
         return false;
     }
 
+    private boolean readContentParameters(int startIndex, int leftToRead, int accumulator) {
+
+        int totalRead = 0;
+
+        if (leftToRead > 0) {
+            byte nextByte = wspData[startIndex];
+            String value = null;
+            String param = null;
+            if ((nextByte & 0x80) == 0x00 && nextByte > 31) { // untyped
+                decodeTokenText(startIndex);
+                param = stringValue;
+                totalRead += dataLength;
+            } else { // typed
+                if (decodeIntegerValue(startIndex)) {
+                    totalRead += dataLength;
+                    int wellKnownParameterValue = (int) unsigned32bit;
+                    param = WELL_KNOWN_PARAMETERS.get(wellKnownParameterValue);
+                    if (param == null) {
+                        param = "unassigned/0x" + Long.toHexString(wellKnownParameterValue);
+                    }
+                    // special case for the "Q" parameter, value is a uintvar
+                    if (wellKnownParameterValue == Q_VALUE) {
+                        if (decodeUintvarInteger(startIndex + totalRead)) {
+                            totalRead += dataLength;
+                            value = String.valueOf(unsigned32bit);
+                            contentParameters.put(param, value);
+                            return readContentParameters(startIndex + totalRead, leftToRead
+                                                            - totalRead, accumulator + totalRead);
+                        } else {
+                            return false;
+                        }
+                    }
+                } else {
+                    return false;
+                }
+            }
+
+            if (decodeNoValue(startIndex + totalRead)) {
+                totalRead += dataLength;
+                value = null;
+            } else if (decodeIntegerValue(startIndex + totalRead)) {
+                totalRead += dataLength;
+                int intValue = (int) unsigned32bit;
+                if (intValue == 0) {
+                    value = "";
+                } else {
+                    value = String.valueOf(intValue);
+                }
+            } else {
+                decodeTokenText(startIndex + totalRead);
+                totalRead += dataLength;
+                value = stringValue;
+                if (value.startsWith("\"")) {
+                    // quoted string, so remove the quote
+                    value = value.substring(1);
+                }
+            }
+            contentParameters.put(param, value);
+            return readContentParameters(startIndex + totalRead, leftToRead - totalRead,
+                                            accumulator + totalRead);
+
+        } else {
+            dataLength = accumulator;
+            return true;
+        }
+    }
+
+    /**
+     * Check if the next byte is No-Value
+     *
+     * @param startIndex The starting position of the "Content length" in this pdu
+     *
+     * @return true if and only if the next byte is 0x00
+     */
+    private boolean decodeNoValue(int startIndex) {
+        if (wspData[startIndex] == 0) {
+            dataLength = 1;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Populate stringValue with the mime type corresponding to the value in unsigned32bit
+     *
+     * Sets unsigned32bit to -1 if stringValue is already populated
+     */
+    private void expandWellKnownMimeType() {
+        if (stringValue == null) {
+            int binaryContentType = (int) unsigned32bit;
+            stringValue = WELL_KNOWN_MIME_TYPES.get(binaryContentType);
+        } else {
+            unsigned32bit = -1;
+        }
+    }
+
     /**
      * Decode the "Content length" type for WSP pdu
      *
@@ -274,7 +565,7 @@
      *
      * @return false when error(not a Content length) occur
      *         return value can be retrieved by getValue32() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeContentLength(int startIndex) {
         return decodeIntegerValue(startIndex);
@@ -287,7 +578,7 @@
      *
      * @return false when error(not a Content location) occur
      *         return value can be retrieved by getValueString() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeContentLocation(int startIndex) {
         return decodeTextString(startIndex);
@@ -300,7 +591,8 @@
      *
      * @return false when error(not a X-Wap-Application-Id) occur
      *         return value can be retrieved first by getValueString() and second by getValue32()
-     *         method length of data in pdu can be retrieved by getValue32() method
+     *         method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeXWapApplicationId(int startIndex) {
         if (decodeIntegerValue(startIndex) == true) {
@@ -317,7 +609,7 @@
      *
      * @return false when error(not a X-Wap-Content-URI) occur
      *         return value can be retrieved by getValueString() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeXWapContentURI(int startIndex) {
         return decodeTextString(startIndex);
@@ -330,7 +622,7 @@
      *
      * @return false when error(not a X-Wap-Initiator-URI) occur
      *         return value can be retrieved by getValueString() method
-     *         length of data in pdu can be retrieved by getValue32() method
+     *         length of data in pdu can be retrieved by getDecodedDataLength() method
      */
     public boolean decodeXWapInitiatorURI(int startIndex) {
         return decodeTextString(startIndex);
@@ -356,4 +648,18 @@
     public String getValueString() {
         return stringValue;
     }
+
+    /**
+     * Any parameters encountered as part of a decodeContentType() invocation.
+     *
+     * @return a map of content parameters keyed by their names, or null if
+     *         decodeContentType() has not been called If any unassigned
+     *         well-known parameters are encountered, the key of the map will be
+     *         'unassigned/0x...', where '...' is the hex value of the
+     *         unassigned parameter.  If a parameter has No-Value the value will be null.
+     *
+     */
+    public HashMap<String, String> getContentParameters() {
+        return contentParameters;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java b/telephony/java/com/android/internal/telephony/cat/AppInterface.java
similarity index 86%
rename from telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java
rename to telephony/java/com/android/internal/telephony/cat/AppInterface.java
index 58f1f97..2eb6ccb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java
+++ b/telephony/java/com/android/internal/telephony/cat/AppInterface.java
@@ -14,29 +14,29 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 /**
- * Interface for communication between STK App and STK Telephony
+ * Interface for communication between STK App and CAT Telephony
  *
  * {@hide}
  */
 public interface AppInterface {
 
     /*
-     * Intent's actions which are broadcasted by the Telephony once a new STK
+     * Intent's actions which are broadcasted by the Telephony once a new CAT
      * proactive command, session end arrive.
      */
-    public static final String STK_CMD_ACTION =
+    public static final String CAT_CMD_ACTION =
                                     "android.intent.action.stk.command";
-    public static final String STK_SESSION_END_ACTION =
+    public static final String CAT_SESSION_END_ACTION =
                                     "android.intent.action.stk.session_end";
 
     /*
      * Callback function from app to telephony to pass a result code and user's
-     * input back to the SIM.
+     * input back to the ICC.
      */
-    void onCmdResponse(StkResponseMessage resMsg);
+    void onCmdResponse(CatResponseMessage resMsg);
 
     /*
      * Enumeration for representing "Type of Command" of proactive commands.
@@ -58,7 +58,8 @@
         SET_UP_EVENT_LIST(0x05),
         SET_UP_IDLE_MODE_TEXT(0x28),
         SET_UP_MENU(0x25),
-        SET_UP_CALL(0x10);
+        SET_UP_CALL(0x10),
+        PROVIDE_LOCAL_INFORMATION(0x26);
 
         private int mValue;
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java b/telephony/java/com/android/internal/telephony/cat/BerTlv.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java
rename to telephony/java/com/android/internal/telephony/cat/BerTlv.java
index 19d3279..774bfa3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java
+++ b/telephony/java/com/android/internal/telephony/cat/BerTlv.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import java.util.List;
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java b/telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java
similarity index 89%
rename from telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java
rename to telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java
index 5425a43..5155bb2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
- * Class used to pass STK messages from telephony to application. Application
+ * Class used to pass CAT messages from telephony to application. Application
  * should call getXXX() to get commands's specific values.
  *
  */
-public class StkCmdMessage implements Parcelable {
+public class CatCmdMessage implements Parcelable {
     // members
     CommandDetails mCmdDet;
     private TextMessage mTextMsg;
@@ -50,7 +50,7 @@
         public TextMessage callMsg;
     }
 
-    StkCmdMessage(CommandParams cmdParams) {
+    CatCmdMessage(CommandParams cmdParams) {
         mCmdDet = cmdParams.cmdDet;
         switch(getCmdType()) {
         case SET_UP_MENU:
@@ -88,7 +88,7 @@
         }
     }
 
-    public StkCmdMessage(Parcel in) {
+    public CatCmdMessage(Parcel in) {
         mCmdDet = in.readParcelable(null);
         mTextMsg = in.readParcelable(null);
         mMenu = in.readParcelable(null);
@@ -130,13 +130,13 @@
         }
     }
 
-    public static final Parcelable.Creator<StkCmdMessage> CREATOR = new Parcelable.Creator<StkCmdMessage>() {
-        public StkCmdMessage createFromParcel(Parcel in) {
-            return new StkCmdMessage(in);
+    public static final Parcelable.Creator<CatCmdMessage> CREATOR = new Parcelable.Creator<CatCmdMessage>() {
+        public CatCmdMessage createFromParcel(Parcel in) {
+            return new CatCmdMessage(in);
         }
 
-        public StkCmdMessage[] newArray(int size) {
-            return new StkCmdMessage[size];
+        public CatCmdMessage[] newArray(int size) {
+            return new CatCmdMessage[size];
         }
     };
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java b/telephony/java/com/android/internal/telephony/cat/CatException.java
similarity index 80%
rename from telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
rename to telephony/java/com/android/internal/telephony/cat/CatException.java
index 86de366..1bf1369 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatException.java
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.util.AndroidException;
 
 
 /**
- * Base class for all the exceptions in STK service.
+ * Base class for all the exceptions in CAT service.
  *
  * {@hide}
  */
-class StkException extends AndroidException {
-    public StkException() {
+class CatException extends AndroidException {
+    public CatException() {
         super();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java b/telephony/java/com/android/internal/telephony/cat/CatLog.java
similarity index 84%
rename from telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java
rename to telephony/java/com/android/internal/telephony/cat/CatLog.java
index bd6bc8f..e19ff43 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatLog.java
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.util.Log;
 
-public abstract class StkLog {
+public abstract class CatLog {
     static final boolean DEBUG = true;
 
     public static void d(Object caller, String msg) {
@@ -27,7 +27,7 @@
         }
 
         String className = caller.getClass().getName();
-        Log.d("STK", className.substring(className.lastIndexOf('.') + 1) + ": "
+        Log.d("CAT", className.substring(className.lastIndexOf('.') + 1) + ": "
                 + msg);
     }
 
@@ -36,6 +36,6 @@
             return;
         }
 
-        Log.d("STK", caller + ": " + msg);
+        Log.d("CAT", caller + ": " + msg);
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkResponseMessage.java b/telephony/java/com/android/internal/telephony/cat/CatResponseMessage.java
similarity index 91%
rename from telephony/java/com/android/internal/telephony/gsm/stk/StkResponseMessage.java
rename to telephony/java/com/android/internal/telephony/cat/CatResponseMessage.java
index 04a52e6..cfcac36 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkResponseMessage.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatResponseMessage.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
-public class StkResponseMessage {
+public class CatResponseMessage {
         CommandDetails cmdDet = null;
         ResultCode resCode  = ResultCode.OK;
         int usersMenuSelection = 0;
@@ -24,7 +24,7 @@
         boolean usersYesNoSelection = false;
         boolean usersConfirm = false;
 
-        public StkResponseMessage(StkCmdMessage cmdMsg) {
+        public CatResponseMessage(CatCmdMessage cmdMsg) {
             this.cmdDet = cmdMsg.mCmdDet;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
similarity index 68%
rename from telephony/java/com/android/internal/telephony/gsm/stk/StkService.java
rename to telephony/java/com/android/internal/telephony/cat/CatService.java
index 29ed95c..1e23e34 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.content.Context;
 import android.content.Intent;
@@ -22,12 +22,13 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
+import android.os.SystemProperties;
 
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.gsm.SimCard;
-import com.android.internal.telephony.gsm.SIMFileHandler;
-import com.android.internal.telephony.gsm.SIMRecords;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccRecords;
 
 import android.util.Config;
 
@@ -111,17 +112,17 @@
  *
  * {@hide}
  */
-public class StkService extends Handler implements AppInterface {
+public class CatService extends Handler implements AppInterface {
 
     // Class members
-    private static SIMRecords mSimRecords;
+    private static IccRecords mIccRecords;
 
     // Service members.
-    private static StkService sInstance;
+    private static CatService sInstance;
     private CommandsInterface mCmdIf;
     private Context mContext;
-    private StkCmdMessage mCurrntCmd = null;
-    private StkCmdMessage mMenuCmd = null;
+    private CatCmdMessage mCurrntCmd = null;
+    private CatCmdMessage mMenuCmd = null;
 
     private RilMessageDecoder mMsgDecoder = null;
 
@@ -136,7 +137,7 @@
     static final int MSG_ID_RIL_MSG_DECODED          = 10;
 
     // Events to signal SIM presence or absent in the device.
-    private static final int MSG_ID_SIM_LOADED       = 20;
+    private static final int MSG_ID_ICC_RECORDS_LOADED       = 20;
 
     private static final int DEV_ID_KEYPAD      = 0x01;
     private static final int DEV_ID_DISPLAY     = 0x02;
@@ -146,10 +147,10 @@
     private static final int DEV_ID_NETWORK     = 0x83;
 
     /* Intentionally private for singleton */
-    private StkService(CommandsInterface ci, SIMRecords sr, Context context,
-            SIMFileHandler fh, SimCard sc) {
-        if (ci == null || sr == null || context == null || fh == null
-                || sc == null) {
+    private CatService(CommandsInterface ci, IccRecords ir, Context context,
+            IccFileHandler fh, IccCard ic) {
+        if (ci == null || ir == null || context == null || fh == null
+                || ic == null) {
             throw new NullPointerException(
                     "Service: Input parameters must not be null");
         }
@@ -160,33 +161,33 @@
         mMsgDecoder = RilMessageDecoder.getInstance(this, fh);
 
         // Register ril events handling.
-        mCmdIf.setOnStkSessionEnd(this, MSG_ID_SESSION_END, null);
-        mCmdIf.setOnStkProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null);
-        mCmdIf.setOnStkEvent(this, MSG_ID_EVENT_NOTIFY, null);
-        mCmdIf.setOnStkCallSetUp(this, MSG_ID_CALL_SETUP, null);
+        mCmdIf.setOnCatSessionEnd(this, MSG_ID_SESSION_END, null);
+        mCmdIf.setOnCatProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null);
+        mCmdIf.setOnCatEvent(this, MSG_ID_EVENT_NOTIFY, null);
+        mCmdIf.setOnCatCallSetUp(this, MSG_ID_CALL_SETUP, null);
         //mCmdIf.setOnSimRefresh(this, MSG_ID_REFRESH, null);
 
-        mSimRecords = sr;
+        mIccRecords = ir;
 
         // Register for SIM ready event.
-        mSimRecords.registerForRecordsLoaded(this, MSG_ID_SIM_LOADED, null);
+        mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null);
 
         mCmdIf.reportStkServiceIsRunning(null);
-        StkLog.d(this, "StkService: is running");
+        CatLog.d(this, "Is running");
     }
 
     public void dispose() {
-        mSimRecords.unregisterForRecordsLoaded(this);
-        mCmdIf.unSetOnStkSessionEnd(this);
-        mCmdIf.unSetOnStkProactiveCmd(this);
-        mCmdIf.unSetOnStkEvent(this);
-        mCmdIf.unSetOnStkCallSetUp(this);
+        mIccRecords.unregisterForRecordsLoaded(this);
+        mCmdIf.unSetOnCatSessionEnd(this);
+        mCmdIf.unSetOnCatProactiveCmd(this);
+        mCmdIf.unSetOnCatEvent(this);
+        mCmdIf.unSetOnCatCallSetUp(this);
 
         this.removeCallbacksAndMessages(null);
     }
 
     protected void finalize() {
-        StkLog.d(this, "Service finalized");
+        CatLog.d(this, "Service finalized");
     }
 
     private void handleRilMsg(RilMessage rilMsg) {
@@ -241,55 +242,53 @@
      *
      */
     private void handleProactiveCommand(CommandParams cmdParams) {
-        StkLog.d(this, cmdParams.getCommandType().name());
+        CatLog.d(this, cmdParams.getCommandType().name());
 
-        StkCmdMessage cmdMsg = new StkCmdMessage(cmdParams);
+        CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams);
         switch (cmdParams.getCommandType()) {
-        case SET_UP_MENU:
-            if (removeMenu(cmdMsg.getMenu())) {
-                mMenuCmd = null;
-            } else {
-                mMenuCmd = cmdMsg;
-            }
-            sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0,
-                    null);
-            break;
-        case DISPLAY_TEXT:
-            // when application is not required to respond, send an immediate
-            // response.
-            if (!cmdMsg.geTextMessage().responseNeeded) {
-                sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false,
-                        0, null);
-            }
-            break;
-        case REFRESH:
-            // ME side only handles refresh commands which meant to remove IDLE
-            // MODE TEXT.
-            cmdParams.cmdDet.typeOfCommand = CommandType.SET_UP_IDLE_MODE_TEXT
-                    .value();
-            break;
-        case SET_UP_IDLE_MODE_TEXT:
-            sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false,
-                    0, null);
-            break;
-        case LAUNCH_BROWSER:
-        case SELECT_ITEM:
-        case GET_INPUT:
-        case GET_INKEY:
-        case SEND_DTMF:
-        case SEND_SMS:
-        case SEND_SS:
-        case SEND_USSD:
-        case PLAY_TONE:
-        case SET_UP_CALL:
-            // nothing to do on telephony!
-            break;
-        default:
-            StkLog.d(this, "Unsupported command");
-            return;
+            case SET_UP_MENU:
+                if (removeMenu(cmdMsg.getMenu())) {
+                    mMenuCmd = null;
+                } else {
+                    mMenuCmd = cmdMsg;
+                }
+                sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+                break;
+            case DISPLAY_TEXT:
+                // when application is not required to respond, send an immediate response.
+                if (!cmdMsg.geTextMessage().responseNeeded) {
+                    sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+                }
+                break;
+            case REFRESH:
+                // ME side only handles refresh commands which meant to remove IDLE
+                // MODE TEXT.
+                cmdParams.cmdDet.typeOfCommand = CommandType.SET_UP_IDLE_MODE_TEXT.value();
+                break;
+            case SET_UP_IDLE_MODE_TEXT:
+                sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+                break;
+            case PROVIDE_LOCAL_INFORMATION:
+                sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+                return;
+            case LAUNCH_BROWSER:
+            case SELECT_ITEM:
+            case GET_INPUT:
+            case GET_INKEY:
+            case SEND_DTMF:
+            case SEND_SMS:
+            case SEND_SS:
+            case SEND_USSD:
+            case PLAY_TONE:
+            case SET_UP_CALL:
+                // nothing to do on telephony!
+                break;
+            default:
+                CatLog.d(this, "Unsupported command");
+                return;
         }
         mCurrntCmd = cmdMsg;
-        Intent intent = new Intent(AppInterface.STK_CMD_ACTION);
+        Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
         intent.putExtra("STK CMD", cmdMsg);
         mContext.sendBroadcast(intent);
     }
@@ -299,10 +298,10 @@
      *
      */
     private void handleSessionEnd() {
-        StkLog.d(this, "SESSION END");
+        CatLog.d(this, "SESSION END");
 
         mCurrntCmd = mMenuCmd;
-        Intent intent = new Intent(AppInterface.STK_SESSION_END_ACTION);
+        Intent intent = new Intent(AppInterface.CAT_SESSION_END_ACTION);
         mContext.sendBroadcast(intent);
     }
 
@@ -315,6 +314,11 @@
         }
         ByteArrayOutputStream buf = new ByteArrayOutputStream();
 
+        Input cmdInput = null;
+        if (mCurrntCmd != null) {
+            cmdInput = mCurrntCmd.geInput();
+        }
+
         // command details
         int tag = ComprehensionTlvTag.COMMAND_DETAILS.value();
         if (cmdDet.compRequired) {
@@ -327,7 +331,13 @@
         buf.write(cmdDet.commandQualifier);
 
         // device identities
-        tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value();
+        // According to TS102.223/TS31.111 section 6.8 Structure of
+        // TERMINAL RESPONSE, "For all SIMPLE-TLV objects with Min=N,
+        // the ME should set the CR(comprehension required) flag to
+        // comprehension not required.(CR=0)"
+        // Since DEVICE_IDENTITIES and DURATION TLVs have Min=N,
+        // the CR flag is not set.
+        tag = ComprehensionTlvTag.DEVICE_IDENTITIES.value();
         buf.write(tag);
         buf.write(0x02); // length
         buf.write(DEV_ID_TERMINAL); // source device id
@@ -348,17 +358,65 @@
         // Fill optional data for each corresponding command
         if (resp != null) {
             resp.format(buf);
+        } else {
+            encodeOptionalTags(cmdDet, resultCode, cmdInput, buf);
         }
 
         byte[] rawData = buf.toByteArray();
         String hexString = IccUtils.bytesToHexString(rawData);
         if (Config.LOGD) {
-            StkLog.d(this, "TERMINAL RESPONSE: " + hexString);
+            CatLog.d(this, "TERMINAL RESPONSE: " + hexString);
         }
 
         mCmdIf.sendTerminalResponse(hexString, null);
     }
 
+    private void encodeOptionalTags(CommandDetails cmdDet,
+            ResultCode resultCode, Input cmdInput, ByteArrayOutputStream buf) {
+        switch (AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) {
+            case GET_INKEY:
+                // ETSI TS 102 384,27.22.4.2.8.4.2.
+                // If it is a response for GET_INKEY command and the response timeout
+                // occured, then add DURATION TLV for variable timeout case.
+                if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
+                    (cmdInput != null) && (cmdInput.duration != null)) {
+                    getInKeyResponse(buf, cmdInput);
+                }
+                break;
+            case PROVIDE_LOCAL_INFORMATION:
+                if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
+                    (resultCode.value() == ResultCode.OK.value())) {
+                    getPliResponse(buf);
+                }
+                break;
+            default:
+                CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
+                break;
+        }
+    }
+
+    private void getInKeyResponse(ByteArrayOutputStream buf, Input cmdInput) {
+        int tag = ComprehensionTlvTag.DURATION.value();
+
+        buf.write(tag);
+        buf.write(0x02); // length
+        buf.write(cmdInput.duration.timeUnit.SECOND.value()); // Time (Unit,Seconds)
+        buf.write(cmdInput.duration.timeInterval); // Time Duration
+    }
+
+    private void getPliResponse(ByteArrayOutputStream buf) {
+
+        // Locale Language Setting
+        String lang = SystemProperties.get("persist.sys.language");
+
+        if (lang != null) {
+            // tag
+            int tag = ComprehensionTlvTag.LANGUAGE.value();
+            buf.write(tag);
+            ResponseData.writeLength(buf, lang.length());
+            buf.write(lang.getBytes(), 0, lang.length());
+        }
+    }
 
     private void sendMenuSelection(int menuId, boolean helpRequired) {
 
@@ -446,35 +504,35 @@
     }
 
     /**
-     * Used for instantiating/updating the Service from the GsmPhone constructor.
+     * Used for instantiating/updating the Service from the GsmPhone or CdmaPhone constructor.
      *
      * @param ci CommandsInterface object
-     * @param sr SIMRecords object
+     * @param ir IccRecords object
      * @param context phone app context
-     * @param fh SIM file handler
-     * @param sc GSM SIM card
+     * @param fh Icc file handler
+     * @param ic Icc card
      * @return The only Service object in the system
      */
-    public static StkService getInstance(CommandsInterface ci, SIMRecords sr,
-            Context context, SIMFileHandler fh, SimCard sc) {
+    public static CatService getInstance(CommandsInterface ci, IccRecords ir,
+            Context context, IccFileHandler fh, IccCard ic) {
         if (sInstance == null) {
-            if (ci == null || sr == null || context == null || fh == null
-                    || sc == null) {
+            if (ci == null || ir == null || context == null || fh == null
+                    || ic == null) {
                 return null;
             }
-            HandlerThread thread = new HandlerThread("Stk Telephony service");
+            HandlerThread thread = new HandlerThread("Cat Telephony service");
             thread.start();
-            sInstance = new StkService(ci, sr, context, fh, sc);
-            StkLog.d(sInstance, "NEW sInstance");
-        } else if ((sr != null) && (mSimRecords != sr)) {
-            StkLog.d(sInstance, "Reinitialize the Service with SIMRecords");
-            mSimRecords = sr;
+            sInstance = new CatService(ci, ir, context, fh, ic);
+            CatLog.d(sInstance, "NEW sInstance");
+        } else if ((ir != null) && (mIccRecords != ir)) {
+            CatLog.d(sInstance, "Reinitialize the Service with SIMRecords");
+            mIccRecords = ir;
 
             // re-Register for SIM ready event.
-            mSimRecords.registerForRecordsLoaded(sInstance, MSG_ID_SIM_LOADED, null);
-            StkLog.d(sInstance, "sr changed reinitialize and return current sInstance");
+            mIccRecords.registerForRecordsLoaded(sInstance, MSG_ID_ICC_RECORDS_LOADED, null);
+            CatLog.d(sInstance, "sr changed reinitialize and return current sInstance");
         } else {
-            StkLog.d(sInstance, "Return current sInstance");
+            CatLog.d(sInstance, "Return current sInstance");
         }
         return sInstance;
     }
@@ -496,7 +554,7 @@
         case MSG_ID_PROACTIVE_COMMAND:
         case MSG_ID_EVENT_NOTIFY:
         case MSG_ID_REFRESH:
-            StkLog.d(this, "ril message arrived");
+            CatLog.d(this, "ril message arrived");
             String data = null;
             if (msg.obj != null) {
                 AsyncResult ar = (AsyncResult) msg.obj;
@@ -513,20 +571,20 @@
         case MSG_ID_CALL_SETUP:
             mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, null));
             break;
-        case MSG_ID_SIM_LOADED:
+        case MSG_ID_ICC_RECORDS_LOADED:
             break;
         case MSG_ID_RIL_MSG_DECODED:
             handleRilMsg((RilMessage) msg.obj);
             break;
         case MSG_ID_RESPONSE:
-            handleCmdResponse((StkResponseMessage) msg.obj);
+            handleCmdResponse((CatResponseMessage) msg.obj);
             break;
         default:
-            throw new AssertionError("Unrecognized STK command: " + msg.what);
+            throw new AssertionError("Unrecognized CAT command: " + msg.what);
         }
     }
 
-    public synchronized void onCmdResponse(StkResponseMessage resMsg) {
+    public synchronized void onCmdResponse(CatResponseMessage resMsg) {
         if (resMsg == null) {
             return;
         }
@@ -535,7 +593,7 @@
         msg.sendToTarget();
     }
 
-    private boolean validateResponse(StkResponseMessage resMsg) {
+    private boolean validateResponse(CatResponseMessage resMsg) {
         if (mCurrntCmd != null) {
             return (resMsg.cmdDet.compareTo(mCurrntCmd.mCmdDet));
         }
@@ -548,13 +606,13 @@
                 return true;
             }
         } catch (NullPointerException e) {
-            StkLog.d(this, "Unable to get Menu's items size");
+            CatLog.d(this, "Unable to get Menu's items size");
             return true;
         }
         return false;
     }
 
-    private void handleCmdResponse(StkResponseMessage resMsg) {
+    private void handleCmdResponse(CatResponseMessage resMsg) {
         // Make sure the response details match the last valid command. An invalid
         // response is a one that doesn't have a corresponding proactive command
         // and sending it can "confuse" the baseband/ril.
@@ -563,7 +621,7 @@
         // by the framework inside the history stack. That activity will be
         // available for relaunch using the latest application dialog
         // (long press on the home button). Relaunching that activity can send
-        // the same command's result again to the StkService and can cause it to
+        // the same command's result again to the CatService and can cause it to
         // get out of sync with the SIM.
         if (!validateResponse(resMsg)) {
             return;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java
rename to telephony/java/com/android/internal/telephony/cat/CommandDetails.java
index e81ff98..e3f0798 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java b/telephony/java/com/android/internal/telephony/cat/CommandParams.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java
rename to telephony/java/com/android/internal/telephony/cat/CommandParams.java
index 3da652f..22a5c8c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParams.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.graphics.Bitmap;
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
similarity index 92%
rename from telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java
rename to telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index ce4c459..12204a0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.graphics.Bitmap;
 import android.os.Handler;
 import android.os.Message;
 
 import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.gsm.SIMFileHandler;
+import com.android.internal.telephony.IccFileHandler;
 
 import java.util.Iterator;
 import java.util.List;
@@ -52,8 +52,11 @@
     static final int REFRESH_NAA_INIT                       = 0x03;
     static final int REFRESH_UICC_RESET                     = 0x04;
 
+    // Command Qualifier values for PLI command
+    static final int LANGUAGE_SETTING                       = 0x04;
+
     static synchronized CommandParamsFactory getInstance(RilMessageDecoder caller,
-            SIMFileHandler fh) {
+            IccFileHandler fh) {
         if (sInstance != null) {
             return sInstance;
         }
@@ -63,7 +66,7 @@
         return null;
     }
 
-    private CommandParamsFactory(RilMessageDecoder caller, SIMFileHandler fh) {
+    private CommandParamsFactory(RilMessageDecoder caller, IccFileHandler fh) {
         mCaller = caller;
         mIconLoader = IconLoader.getInstance(this, fh);
     }
@@ -79,7 +82,7 @@
                 try {
                     cmdDet = ValueParser.retrieveCommandDetails(ctlvCmdDet);
                 } catch (ResultException e) {
-                    StkLog.d(this, "Failed to procees command details");
+                    CatLog.d(this, "Failed to procees command details");
                 }
             }
         }
@@ -112,7 +115,10 @@
         AppInterface.CommandType cmdType = AppInterface.CommandType
                 .fromInt(cmdDet.typeOfCommand);
         if (cmdType == null) {
-            sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD);
+            // This PROACTIVE COMMAND is presently not handled. Hence set
+            // result code as BEYOND_TERMINAL_CAPABILITY in TR.
+            mCmdParams = new CommandParams(cmdDet);
+            sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
             return;
         }
 
@@ -155,10 +161,13 @@
              case PLAY_TONE:
                 cmdPending = processPlayTone(cmdDet, ctlvs);
                 break;
+             case PROVIDE_LOCAL_INFORMATION:
+                cmdPending = processProvideLocalInfo(cmdDet, ctlvs);
+                break;
             default:
                 // unsupported proactive commands
                 mCmdParams = new CommandParams(cmdDet);
-                sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD);
+                sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
                 return;
             }
         } catch (ResultException e) {
@@ -259,7 +268,7 @@
             List<ComprehensionTlv> ctlvs)
             throws ResultException {
 
-        StkLog.d(this, "process DisplayText");
+        CatLog.d(this, "process DisplayText");
 
         TextMessage textMsg = new TextMessage();
         IconId iconId = null;
@@ -319,7 +328,7 @@
     private boolean processSetUpIdleModeText(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process SetUpIdleModeText");
+        CatLog.d(this, "process SetUpIdleModeText");
 
         TextMessage textMsg = new TextMessage();
         IconId iconId = null;
@@ -362,7 +371,7 @@
     private boolean processGetInkey(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process GetInkey");
+        CatLog.d(this, "process GetInkey");
 
         Input input = new Input();
         IconId iconId = null;
@@ -380,6 +389,12 @@
             iconId = ValueParser.retrieveIconId(ctlv);
         }
 
+        // parse duration
+        ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs);
+        if (ctlv != null) {
+            input.duration = ValueParser.retrieveDuration(ctlv);
+        }
+
         input.minLen = 1;
         input.maxLen = 1;
 
@@ -412,7 +427,7 @@
     private boolean processGetInput(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process GetInput");
+        CatLog.d(this, "process GetInput");
 
         Input input = new Input();
         IconId iconId = null;
@@ -476,7 +491,7 @@
     private boolean processRefresh(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) {
 
-        StkLog.d(this, "process Refresh");
+        CatLog.d(this, "process Refresh");
 
         // REFRESH proactive command is rerouted by the baseband and handled by
         // the telephony layer. IDLE TEXT should be removed for a REFRESH command
@@ -505,7 +520,7 @@
     private boolean processSelectItem(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process SelectItem");
+        CatLog.d(this, "process SelectItem");
 
         Menu menu = new Menu();
         IconId titleIconId = null;
@@ -534,7 +549,7 @@
 
         ctlv = searchForTag(ComprehensionTlvTag.ITEM_ID, ctlvs);
         if (ctlv != null) {
-            // STK items are listed 1...n while list start at 0, need to
+            // CAT items are listed 1...n while list start at 0, need to
             // subtract one.
             menu.defaultItem = ValueParser.retrieveItemId(ctlv) - 1;
         }
@@ -602,7 +617,7 @@
     private boolean processEventNotify(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process EventNotify");
+        CatLog.d(this, "process EventNotify");
 
         TextMessage textMsg = new TextMessage();
         IconId iconId = null;
@@ -645,7 +660,7 @@
     private boolean processSetUpEventList(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) {
 
-        StkLog.d(this, "process SetUpEventList");
+        CatLog.d(this, "process SetUpEventList");
         //
         // ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.EVENT_LIST,
         // ctlvs);
@@ -670,10 +685,10 @@
      *         asynchronous processing is required.
      * @throws ResultException
      */
-     private boolean processLaunchBrowser(CommandDetails cmdDet,
+    private boolean processLaunchBrowser(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process LaunchBrowser");
+        CatLog.d(this, "process LaunchBrowser");
 
         TextMessage confirmMsg = new TextMessage();
         IconId iconId = null;
@@ -744,10 +759,10 @@
      *         asynchronous processing is required.t
      * @throws ResultException
      */
-     private boolean processPlayTone(CommandDetails cmdDet,
+    private boolean processPlayTone(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
 
-        StkLog.d(this, "process PlayTone");
+        CatLog.d(this, "process PlayTone");
 
         Tone tone = null;
         TextMessage textMsg = new TextMessage();
@@ -810,9 +825,9 @@
      * @return true if the command is processing is pending and additional
      *         asynchronous processing is required.
      */
-     private boolean processSetupCall(CommandDetails cmdDet,
+    private boolean processSetupCall(CommandDetails cmdDet,
             List<ComprehensionTlv> ctlvs) throws ResultException {
-        StkLog.d(this, "process SetupCall");
+        CatLog.d(this, "process SetupCall");
 
         Iterator<ComprehensionTlv> iter = ctlvs.iterator();
         ComprehensionTlv ctlv = null;
@@ -863,4 +878,20 @@
         }
         return false;
     }
+
+    private boolean processProvideLocalInfo(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs)
+            throws ResultException {
+        CatLog.d(this, "process ProvideLocalInfo");
+        switch (cmdDet.commandQualifier) {
+            case LANGUAGE_SETTING:
+                CatLog.d(this, "PLI [LANGUAGE_SETTING]");
+                mCmdParams = new CommandParams(cmdDet);
+                break;
+            default:
+                CatLog.d(this, "PLI[" + cmdDet.commandQualifier + "] Command Not Supported");
+                mCmdParams = new CommandParams(cmdDet);
+                throw new ResultException(ResultCode.BEYOND_TERMINAL_CAPABILITY);
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java b/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java
rename to telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
index ffde6a3..99f662d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java
+++ b/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Duration.java b/telephony/java/com/android/internal/telephony/cat/Duration.java
similarity index 94%
rename from telephony/java/com/android/internal/telephony/gsm/stk/Duration.java
rename to telephony/java/com/android/internal/telephony/cat/Duration.java
index 9d8cc97..e8cd404 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/Duration.java
+++ b/telephony/java/com/android/internal/telephony/cat/Duration.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 
 
 /**
- * Class for representing "Duration" object for STK.
+ * Class for representing "Duration" object for CAT.
  *
  * {@hide}
  */
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/FontSize.java b/telephony/java/com/android/internal/telephony/cat/FontSize.java
similarity index 96%
rename from telephony/java/com/android/internal/telephony/gsm/stk/FontSize.java
rename to telephony/java/com/android/internal/telephony/cat/FontSize.java
index bd4f49f..02c7ea0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/FontSize.java
+++ b/telephony/java/com/android/internal/telephony/cat/FontSize.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java b/telephony/java/com/android/internal/telephony/cat/IconLoader.java
similarity index 95%
rename from telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java
rename to telephony/java/com/android/internal/telephony/cat/IconLoader.java
index fc02d2a..2fa1811 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java
+++ b/telephony/java/com/android/internal/telephony/cat/IconLoader.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
-import com.android.internal.telephony.gsm.SIMFileHandler;
+import com.android.internal.telephony.IccFileHandler;
 
 import android.graphics.Bitmap;
 import android.graphics.Color;
@@ -40,7 +40,7 @@
     private ImageDescriptor mId = null;
     private Bitmap mCurrentIcon = null;
     private int mRecordNumber;
-    private SIMFileHandler mSimFH = null;
+    private IccFileHandler mSimFH = null;
     private Message mEndMsg = null;
     private byte[] mIconData = null;
     // multi icons state members
@@ -68,19 +68,19 @@
     private static final int CLUT_ENTRY_SIZE = 3;
 
 
-    private IconLoader(Looper looper , SIMFileHandler fh) {
+    private IconLoader(Looper looper , IccFileHandler fh) {
         super(looper);
         mSimFH = fh;
 
         mIconsCache = new HashMap<Integer, Bitmap>(50);
     }
 
-    static IconLoader getInstance(Handler caller, SIMFileHandler fh) {
+    static IconLoader getInstance(Handler caller, IccFileHandler fh) {
         if (sLoader != null) {
             return sLoader;
         }
         if (fh != null) {
-            HandlerThread thread = new HandlerThread("Stk Icon Loader");
+            HandlerThread thread = new HandlerThread("Cat Icon Loader");
             thread.start();
             return new IconLoader(thread.getLooper(), fh);
         }
@@ -163,7 +163,7 @@
                 break;
             }
         } catch (Exception e) {
-            StkLog.d(this, "Icon load failed");
+            CatLog.d(this, "Icon load failed");
             // post null icon back to the caller.
             postIcon();
         }
@@ -254,7 +254,7 @@
         }
 
         if (pixelIndex != numOfPixels) {
-            StkLog.d("IconLoader", "parseToBnW; size error");
+            CatLog.d("IconLoader", "parseToBnW; size error");
         }
         return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java b/telephony/java/com/android/internal/telephony/cat/ImageDescriptor.java
similarity index 95%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java
rename to telephony/java/com/android/internal/telephony/cat/ImageDescriptor.java
index 880b9e5..711d977 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java
+++ b/telephony/java/com/android/internal/telephony/cat/ImageDescriptor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 /**
  * {@hide}
@@ -69,7 +69,7 @@
 
             d.length = ((rawData[valueIndex++] & 0xff) << 8 | (rawData[valueIndex++] & 0xff));
         } catch (IndexOutOfBoundsException e) {
-            StkLog.d("ImageDescripter", "parse; failed parsing image descriptor");
+            CatLog.d("ImageDescripter", "parse; failed parsing image descriptor");
             d = null;
         }
         return d;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Input.java b/telephony/java/com/android/internal/telephony/cat/Input.java
similarity index 91%
rename from telephony/java/com/android/internal/telephony/gsm/stk/Input.java
rename to telephony/java/com/android/internal/telephony/cat/Input.java
index 19f724b..13a5ad4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/Input.java
+++ b/telephony/java/com/android/internal/telephony/cat/Input.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.graphics.Bitmap;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
- * Container class for STK GET INPUT, GET IN KEY commands parameters.
+ * Container class for CAT GET INPUT, GET IN KEY commands parameters.
  *
  */
 public class Input implements Parcelable {
@@ -36,6 +36,7 @@
     public boolean echo;
     public boolean yesNo;
     public boolean helpAvailable;
+    public Duration duration;
 
     Input() {
         text = "";
@@ -49,6 +50,7 @@
         echo = false;
         yesNo = false;
         helpAvailable = false;
+        duration = null;
     }
 
     private Input(Parcel in) {
@@ -63,6 +65,7 @@
         echo = in.readInt() == 1 ? true : false;
         yesNo = in.readInt() == 1 ? true : false;
         helpAvailable = in.readInt() == 1 ? true : false;
+        duration = in.readParcelable(null);
     }
 
     public int describeContents() {
@@ -81,6 +84,7 @@
         dest.writeInt(echo ? 1 : 0);
         dest.writeInt(yesNo ? 1 : 0);
         dest.writeInt(helpAvailable ? 1 : 0);
+        dest.writeParcelable(duration, 0);
     }
 
     public static final Parcelable.Creator<Input> CREATOR = new Parcelable.Creator<Input>() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Item.java b/telephony/java/com/android/internal/telephony/cat/Item.java
similarity index 97%
rename from telephony/java/com/android/internal/telephony/gsm/stk/Item.java
rename to telephony/java/com/android/internal/telephony/cat/Item.java
index b2f338c..d4702bb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/Item.java
+++ b/telephony/java/com/android/internal/telephony/cat/Item.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.graphics.Bitmap;
 import android.os.Parcel;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/LaunchBrowserMode.java b/telephony/java/com/android/internal/telephony/cat/LaunchBrowserMode.java
similarity index 95%
rename from telephony/java/com/android/internal/telephony/gsm/stk/LaunchBrowserMode.java
rename to telephony/java/com/android/internal/telephony/cat/LaunchBrowserMode.java
index 302273c..af043d1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/LaunchBrowserMode.java
+++ b/telephony/java/com/android/internal/telephony/cat/LaunchBrowserMode.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java b/telephony/java/com/android/internal/telephony/cat/Menu.java
similarity index 96%
rename from telephony/java/com/android/internal/telephony/gsm/stk/Menu.java
rename to telephony/java/com/android/internal/telephony/cat/Menu.java
index 331f69d..7bbae01 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java
+++ b/telephony/java/com/android/internal/telephony/cat/Menu.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.graphics.Bitmap;
 import android.os.Parcel;
@@ -24,7 +24,7 @@
 import java.util.List;
 
 /**
- * Container class for STK menu (SET UP MENU, SELECT ITEM) parameters.
+ * Container class for CAT menu (SET UP MENU, SELECT ITEM) parameters.
  *
  */
 public class Menu implements Parcelable {
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/PresentationType.java b/telephony/java/com/android/internal/telephony/cat/PresentationType.java
similarity index 94%
rename from telephony/java/com/android/internal/telephony/gsm/stk/PresentationType.java
rename to telephony/java/com/android/internal/telephony/cat/PresentationType.java
index 71bdcdc..7c8cd8c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/PresentationType.java
+++ b/telephony/java/com/android/internal/telephony/cat/PresentationType.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java b/telephony/java/com/android/internal/telephony/cat/ResponseData.java
similarity index 90%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java
rename to telephony/java/com/android/internal/telephony/cat/ResponseData.java
index afd1bba..677d66b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java
+++ b/telephony/java/com/android/internal/telephony/cat/ResponseData.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import com.android.internal.telephony.EncodeException;
 import com.android.internal.telephony.GsmAlphabet;
@@ -28,6 +28,16 @@
      * the ByteArrayOutputStream object.
      */
     public abstract void format(ByteArrayOutputStream buf);
+
+    public static void writeLength(ByteArrayOutputStream buf, int length) {
+        // As per ETSI 102.220 Sec7.1.2, if the total length is greater
+        // than 0x7F, it should be coded in two bytes and the first byte
+        // should be 0x81.
+        if (length > 0x7F) {
+            buf.write(0x81);
+        }
+        buf.write(length);
+    }
 }
 
 class SelectItemResponseData extends ResponseData {
@@ -120,7 +130,7 @@
         }
 
         // length - one more for data coding scheme.
-        buf.write(data.length + 1);
+        writeLength(buf, data.length + 1);
 
         // data coding scheme
         if (mIsUcs2) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java b/telephony/java/com/android/internal/telephony/cat/ResultCode.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java
rename to telephony/java/com/android/internal/telephony/cat/ResultCode.java
index b96a524..8544175 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java
+++ b/telephony/java/com/android/internal/telephony/cat/ResultCode.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResultException.java b/telephony/java/com/android/internal/telephony/cat/ResultException.java
similarity index 95%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ResultException.java
rename to telephony/java/com/android/internal/telephony/cat/ResultException.java
index 2eb16c9..1c2cb63 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ResultException.java
+++ b/telephony/java/com/android/internal/telephony/cat/ResultException.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
@@ -22,7 +22,7 @@
  *
  * {@hide}
  */
-public class ResultException extends StkException {
+public class ResultException extends CatException {
     private ResultCode mResult;
     private int mAdditionalInfo;
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
similarity index 87%
rename from telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java
rename to telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
index a82177c..a197c9a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java
+++ b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
-import com.android.internal.telephony.gsm.SIMFileHandler;
+import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccUtils;
 
 import android.os.Handler;
@@ -26,7 +26,7 @@
 
 /**
  * Class used for queuing raw ril messages, decoding them into CommanParams
- * objects and sending the result back to the STK Service.
+ * objects and sending the result back to the CAT Service.
  */
 class RilMessageDecoder extends HierarchicalStateMachine {
 
@@ -51,7 +51,7 @@
      * @param fh
      * @return RilMesssageDecoder
      */
-    public static synchronized RilMessageDecoder getInstance(Handler caller, SIMFileHandler fh) {
+    public static synchronized RilMessageDecoder getInstance(Handler caller, IccFileHandler fh) {
         if (sInstance == null) {
             sInstance = new RilMessageDecoder(caller, fh);
             sInstance.start();
@@ -85,12 +85,12 @@
     }
 
     private void sendCmdForExecution(RilMessage rilMsg) {
-        Message msg = mCaller.obtainMessage(StkService.MSG_ID_RIL_MSG_DECODED,
+        Message msg = mCaller.obtainMessage(CatService.MSG_ID_RIL_MSG_DECODED,
                 new RilMessage(rilMsg));
         msg.sendToTarget();
     }
 
-    private RilMessageDecoder(Handler caller, SIMFileHandler fh) {
+    private RilMessageDecoder(Handler caller, IccFileHandler fh) {
         super("RilMessageDecoder");
 
         addState(mStateStart);
@@ -108,7 +108,7 @@
                     transitionTo(mStateCmdParamsReady);
                 }
             } else {
-                StkLog.d(this, "StateStart unexpected expecting START=" +
+                CatLog.d(this, "StateStart unexpected expecting START=" +
                          CMD_START + " got " + msg.what);
             }
             return true;
@@ -123,7 +123,7 @@
                 sendCmdForExecution(mCurrentRilMessage);
                 transitionTo(mStateStart);
             } else {
-                StkLog.d(this, "StateCmdParamsReady expecting CMD_PARAMS_READY="
+                CatLog.d(this, "StateCmdParamsReady expecting CMD_PARAMS_READY="
                          + CMD_PARAMS_READY + " got " + msg.what);
                 deferMessage(msg);
             }
@@ -136,21 +136,21 @@
 
         mCurrentRilMessage = rilMsg;
         switch(rilMsg.mId) {
-        case StkService.MSG_ID_SESSION_END:
-        case StkService.MSG_ID_CALL_SETUP:
+        case CatService.MSG_ID_SESSION_END:
+        case CatService.MSG_ID_CALL_SETUP:
             mCurrentRilMessage.mResCode = ResultCode.OK;
             sendCmdForExecution(mCurrentRilMessage);
             decodingStarted = false;
             break;
-        case StkService.MSG_ID_PROACTIVE_COMMAND:
-        case StkService.MSG_ID_EVENT_NOTIFY:
-        case StkService.MSG_ID_REFRESH:
+        case CatService.MSG_ID_PROACTIVE_COMMAND:
+        case CatService.MSG_ID_EVENT_NOTIFY:
+        case CatService.MSG_ID_REFRESH:
             byte[] rawData = null;
             try {
                 rawData = IccUtils.hexStringToBytes((String) rilMsg.mData);
             } catch (Exception e) {
                 // zombie messages are dropped
-                StkLog.d(this, "decodeMessageParams dropping zombie messages");
+                CatLog.d(this, "decodeMessageParams dropping zombie messages");
                 decodingStarted = false;
                 break;
             }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/TextAlignment.java b/telephony/java/com/android/internal/telephony/cat/TextAlignment.java
similarity index 96%
rename from telephony/java/com/android/internal/telephony/gsm/stk/TextAlignment.java
rename to telephony/java/com/android/internal/telephony/cat/TextAlignment.java
index c5dd50e..7fb58a5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/TextAlignment.java
+++ b/telephony/java/com/android/internal/telephony/cat/TextAlignment.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/TextAttribute.java b/telephony/java/com/android/internal/telephony/cat/TextAttribute.java
similarity index 96%
rename from telephony/java/com/android/internal/telephony/gsm/stk/TextAttribute.java
rename to telephony/java/com/android/internal/telephony/cat/TextAttribute.java
index ace4300..0dea640 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/TextAttribute.java
+++ b/telephony/java/com/android/internal/telephony/cat/TextAttribute.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/TextColor.java b/telephony/java/com/android/internal/telephony/cat/TextColor.java
similarity index 96%
rename from telephony/java/com/android/internal/telephony/gsm/stk/TextColor.java
rename to telephony/java/com/android/internal/telephony/cat/TextColor.java
index 126fc62..6447e74 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/TextColor.java
+++ b/telephony/java/com/android/internal/telephony/cat/TextColor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 
 /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/TextMessage.java b/telephony/java/com/android/internal/telephony/cat/TextMessage.java
similarity index 97%
rename from telephony/java/com/android/internal/telephony/gsm/stk/TextMessage.java
rename to telephony/java/com/android/internal/telephony/cat/TextMessage.java
index 3b6a09a..5ffd076 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/TextMessage.java
+++ b/telephony/java/com/android/internal/telephony/cat/TextMessage.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.graphics.Bitmap;
 import android.os.Parcel;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Tone.java b/telephony/java/com/android/internal/telephony/cat/Tone.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/Tone.java
rename to telephony/java/com/android/internal/telephony/cat/Tone.java
index b64e777d..27b4489 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/Tone.java
+++ b/telephony/java/com/android/internal/telephony/cat/Tone.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java b/telephony/java/com/android/internal/telephony/cat/ToneSettings.java
similarity index 97%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java
rename to telephony/java/com/android/internal/telephony/cat/ToneSettings.java
index 90cc6c1..6375afb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java
+++ b/telephony/java/com/android/internal/telephony/cat/ToneSettings.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java b/telephony/java/com/android/internal/telephony/cat/ValueParser.java
similarity index 98%
rename from telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java
rename to telephony/java/com/android/internal/telephony/cat/ValueParser.java
index 09a860e..34e4811 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java
+++ b/telephony/java/com/android/internal/telephony/cat/ValueParser.java
@@ -14,11 +14,11 @@
  * the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cat;
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.IccUtils;
-import com.android.internal.telephony.gsm.stk.Duration.TimeUnit;
+import com.android.internal.telephony.cat.Duration.TimeUnit;
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
@@ -182,7 +182,7 @@
      */
     static ItemsIconId retrieveItemsIconId(ComprehensionTlv ctlv)
             throws ResultException {
-        StkLog.d("ValueParser", "retrieveItemsIconId:");
+        CatLog.d("ValueParser", "retrieveItemsIconId:");
         ItemsIconId id = new ItemsIconId();
 
         byte[] rawValue = ctlv.getRawValue();
diff --git a/telephony/java/com/android/internal/telephony/cat/package.html b/telephony/java/com/android/internal/telephony/cat/package.html
new file mode 100644
index 0000000..5b6bfc6
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cat/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Provides classes for ICC Toolkit Service (CAT).
+</BODY>
+</HTML>
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index f48c956..f31bf24 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -42,6 +42,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CommandException;
@@ -108,7 +109,7 @@
     PhoneSubInfo mSubInfo;
     EriManager mEriManager;
     WakeLock mWakeLock;
-
+    CatService mCcatService;
 
     // mNvLoadedRegistrants are informed after the EVENT_NV_READY
     private RegistrantList mNvLoadedRegistrants = new RegistrantList();
@@ -160,6 +161,8 @@
         mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
         mSubInfo = new PhoneSubInfo(this);
         mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
+        mCcatService = CatService.getInstance(mCM, mRuimRecords, mContext,
+                mIccFileHandler, mRuimCard);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
         mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
@@ -220,6 +223,7 @@
             mCM.unregisterForNVReady(this); //EVENT_NV_READY
             mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
             mCM.unSetOnSuppServiceNotification(this);
+            removeCallbacks(mExitEcmRunnable);
 
             mPendingMmis.clear();
 
@@ -235,6 +239,7 @@
             mRuimSmsInterfaceManager.dispose();
             mSubInfo.dispose();
             mEriManager.dispose();
+            mCcatService.dispose();
         }
     }
 
@@ -250,6 +255,8 @@
             this.mCT = null;
             this.mSST = null;
             this.mEriManager = null;
+            this.mCcatService = null;
+            this.mExitEcmRunnable = null;
     }
 
     protected void finalize() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
old mode 100644
new mode 100755
index 2cad6cc..d2a4bd8
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -552,32 +552,53 @@
     }
 
     @Override
-    protected void powerOffRadioSafely(){
-        // clean data connection
+    protected void powerOffRadioSafely() {
         DataConnectionTracker dcTracker = phone.mDataConnection;
 
         Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
-        msg.arg1 = 1; // tearDown is true
         msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
-        dcTracker.sendMessage(msg);
 
-        synchronized(this) {
-            if (!mPendingRadioPowerOffAfterDataOff) {
-                DataConnectionTracker.State currentState = dcTracker.getState();
-                if (currentState != DataConnectionTracker.State.CONNECTED
-                        && currentState != DataConnectionTracker.State.DISCONNECTING
-                        && currentState != DataConnectionTracker.State.INITING) {
-                    if (DBG) log("Data disconnected, turn off radio right away.");
-                    hangupAndPowerOff();
-                }
-                else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
-                    if (DBG) {
-                        log("Wait up to 30 sec for data to disconnect, then turn off radio.");
+        synchronized (this) {
+            if (networkType == ServiceState.RADIO_TECHNOLOGY_1xRTT) {
+                /*
+                 * In 1x CDMA , during radio power off modem will disconnect the
+                 * data call and sends the power down registration message along
+                 * with the data call release message to the network
+                 */
+
+                msg.arg1 = 0; // tearDown is false since modem does it anyway for 1X
+                dcTracker.sendMessage(msg);
+
+                Log.w(LOG_TAG, "Turn off the radio right away");
+                hangupAndPowerOff();
+            } else {
+                if (!mPendingRadioPowerOffAfterDataOff) {
+                    DataConnectionTracker.State currentState = dcTracker.getState();
+                    if (currentState != DataConnectionTracker.State.CONNECTED
+                            && currentState != DataConnectionTracker.State.DISCONNECTING
+                            && currentState != DataConnectionTracker.State.INITING) {
+
+                        msg.arg1 = 0; // tearDown is false as it is not needed.
+                        dcTracker.sendMessage(msg);
+
+                        if (DBG)
+                            log("Data disconnected, turn off radio right away.");
+                        hangupAndPowerOff();
+                    } else {
+                        // clean data connection
+                        msg.arg1 = 1; // tearDown is true
+                        dcTracker.sendMessage(msg);
+
+                        if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
+                            if (DBG) {
+                                log("Wait upto 30s for data to disconnect, then turn off radio.");
+                            }
+                            mPendingRadioPowerOffAfterDataOff = true;
+                        } else {
+                            Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
+                            hangupAndPowerOff();
+                        }
                     }
-                    mPendingRadioPowerOffAfterDataOff = true;
-                } else {
-                    Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
-                    hangupAndPowerOff();
                 }
             }
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
old mode 100755
new mode 100644
index 6f024ed..d563dc8
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -29,6 +29,7 @@
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.util.HexDump;
@@ -138,6 +139,7 @@
         SmsMessage msg = new SmsMessage();
         SmsEnvelope env = new SmsEnvelope();
         CdmaSmsAddress addr = new CdmaSmsAddress();
+        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
         byte[] data;
         byte count;
         int countInt;
@@ -180,15 +182,24 @@
 
         addr.origBytes = data;
 
-        // ignore subaddress
-        p.readInt(); //p_cur->sSubAddress.subaddressType
-        p.readInt(); //p_cur->sSubAddress.odd
-        count = p.readByte(); //p_cur->sSubAddress.number_of_digits
-        //p_cur->sSubAddress.digits[digitCount] :
-        for (int index=0; index < count; index++) {
-            p.readByte();
+        subaddr.type = p.readInt(); // p_cur->sSubAddress.subaddressType
+        subaddr.odd = p.readByte();     // p_cur->sSubAddress.odd
+        count = p.readByte();           // p_cur->sSubAddress.number_of_digits
+
+        if (count < 0) {
+            count = 0;
         }
 
+        // p_cur->sSubAddress.digits[digitCount] :
+
+        data = new byte[count];
+
+        for (int index = 0; index < count; ++index) {
+            data[index] = p.readByte();
+        }
+
+        subaddr.origBytes = data;
+
         /* currently not supported by the modem-lib:
             env.bearerReply
             env.replySeqNo
@@ -210,6 +221,7 @@
 
         // link the the filled objects to the SMS
         env.origAddress = addr;
+        env.origSubaddress = subaddr;
         msg.originatingAddress = addr;
         msg.mEnvelope = env;
 
@@ -818,6 +830,8 @@
         output.write(mEnvelope.teleService);
         output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length);
         output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length);
+        output.write(mEnvelope.origSubaddress.origBytes, 0,
+                mEnvelope.origSubaddress.origBytes.length);
 
         return output.toByteArray();
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
similarity index 64%
copy from telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
copy to telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
index 86de366..f9cebf5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkException.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project. All rights reserved.
+ * Copyright (C) 2010 Code Aurora Forum. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,18 +15,13 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm.stk;
+package com.android.internal.telephony.cdma.sms;
 
-import android.util.AndroidException;
+public class CdmaSmsSubaddress {
+    public int type;
 
+    public byte odd;
 
-/**
- * Base class for all the exceptions in STK service.
- *
- * {@hide}
- */
-class StkException extends AndroidException {
-    public StkException() {
-        super();
-    }
+    public byte[] origBytes;
 }
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index 0dcacc1..4f00163 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -17,6 +17,8 @@
 package com.android.internal.telephony.cdma.sms;
 
 
+import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
+
 public final class SmsEnvelope{
     /**
      * Message Types
@@ -74,17 +76,23 @@
 
     /**
      * The origination address identifies the originator of the SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
+     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
      */
     public CdmaSmsAddress origAddress;
 
     /**
      * The destination address identifies the target of the SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
+     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
      */
     public CdmaSmsAddress destAddress;
 
     /**
+     * The origination subaddress identifies the originator of the SMS message.
+     * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
+     */
+    public CdmaSmsSubaddress origSubaddress;
+
+    /**
      * The 6-bit bearer reply parameter is used to request the return of a
      * SMS Acknowledge Message.
      * (See 3GPP2 C.S0015-B, v2, 3.4.3.5)
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 689a972..3959c67 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -49,6 +49,7 @@
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
 
+import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallForwardInfo;
 import com.android.internal.telephony.CallStateException;
@@ -68,7 +69,6 @@
 import com.android.internal.telephony.PhoneSubInfo;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.UUSInfo;
-import com.android.internal.telephony.gsm.stk.StkService;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.IccVmNotSupportedException;
 
@@ -102,7 +102,7 @@
     GsmSMSDispatcher mSMS;
     SIMRecords mSIMRecords;
     SimCard mSimCard;
-    StkService mStkService;
+    CatService mStkService;
     ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>();
     SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
     SimSmsInterfaceManager mSimSmsIntManager;
@@ -150,7 +150,7 @@
             mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
             mSubInfo = new PhoneSubInfo(this);
         }
-        mStkService = StkService.getInstance(mCM, mSIMRecords, mContext,
+        mStkService = CatService.getInstance(mCM, mSIMRecords, mContext,
                 (SIMFileHandler)mIccFileHandler, mSimCard);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
@@ -968,7 +968,9 @@
     }
 
     public void getCallWaiting(Message onComplete) {
-        mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
+        //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
+        //class parameter in call waiting interrogation  to network
+        mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
     }
 
     public void setCallWaiting(boolean enable, Message onComplete) {
@@ -1221,7 +1223,8 @@
                 // Check if this is a different SIM than the previous one. If so unset the
                 // voice mail number.
                 String imsi = getVmSimImsi();
-                if (imsi != null && !getSubscriberId().equals(imsi)) {
+                String imsiFromSIM = getSubscriberId();
+                if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
                     storeVoiceMailNumber(null);
                     setVmSimImsi(null);
                 }
@@ -1480,4 +1483,7 @@
         Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
     }
 
+    public boolean isCspPlmnEnabled() {
+        return mSIMRecords.isCspPlmnEnabled();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index aa16fa3..fe7a5cb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -44,6 +44,13 @@
 
     //***** Constants
 
+    // Max Size of the Short Code (aka Short String from TS 22.030 6.5.2)
+    static final int MAX_LENGTH_SHORT_CODE = 2;
+
+    // TS 22.030 6.5.2 Every Short String USSD command will end with #-key
+    // (known as #-String)
+    static final char END_OF_USSD_COMMAND = '#';
+
     // From TS 22.030 6.5.2
     static final String ACTION_ACTIVATE = "*";
     static final String ACTION_DEACTIVATE = "#";
@@ -446,22 +453,69 @@
     }
 
     /**
-     * Helper function for newFromDialString.  Returns true if dialString appears to be a short code
-     * AND conditions are correct for it to be treated as such.
+     * Helper function for newFromDialString. Returns true if dialString appears
+     * to be a short code AND conditions are correct for it to be treated as
+     * such.
      */
     static private boolean isShortCode(String dialString, GSMPhone phone) {
         // Refer to TS 22.030 Figure 3.5.3.2:
-        // A 1 or 2 digit "short code" is treated as USSD if it is entered while on a call or
-        // does not satisfy the condition (exactly 2 digits && starts with '1').
-        return ((dialString != null && dialString.length() <= 2)
-                && !PhoneNumberUtils.isEmergencyNumber(dialString)
-                && (phone.isInCall()
-                    || !((dialString.length() == 2 && dialString.charAt(0) == '1')
-                         /* While contrary to TS 22.030, there is strong precedence
-                          * for treating "0" and "00" as call setup strings.
-                          */
-                         || dialString.equals("0")
-                         || dialString.equals("00"))));
+        if (dialString == null) {
+            return false;
+        }
+
+        // Illegal dial string characters will give a ZERO length.
+        // At this point we do not want to crash as any application with
+        // call privileges may send a non dial string.
+        // It return false as when the dialString is equal to NULL.
+        if (dialString.length() == 0) {
+            return false;
+        }
+
+        if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
+            return false;
+        } else {
+            return isShortCodeUSSD(dialString, phone);
+        }
+    }
+
+    /**
+     * Helper function for isShortCode. Returns true if dialString appears to be
+     * a short code and it is a USSD structure
+     *
+     * According to the 3PGG TS 22.030 specification Figure 3.5.3.2: A 1 or 2
+     * digit "short code" is treated as USSD if it is entered while on a call or
+     * does not satisfy the condition (exactly 2 digits && starts with '1'), there
+     * are however exceptions to this rule (see below)
+     *
+     * Exception (1) to Call initiation is: If the user of the device is already in a call
+     * and enters a Short String without any #-key at the end and the length of the Short String is
+     * equal or less then the MAX_LENGTH_SHORT_CODE [constant that is equal to 2]
+     *
+     * The phone shall initiate a USSD/SS commands.
+     *
+     * Exception (2) to Call initiation is: If the user of the device enters one
+     * Digit followed by the #-key. This rule defines this String as the
+     * #-String which is a USSD/SS command.
+     *
+     * The phone shall initiate a USSD/SS command.
+     */
+    static private boolean isShortCodeUSSD(String dialString, GSMPhone phone) {
+        if (dialString != null) {
+            if (phone.isInCall()) {
+                // The maximum length of a Short Code (aka Short String) is 2
+                if (dialString.length() <= MAX_LENGTH_SHORT_CODE) {
+                    return true;
+                }
+            }
+
+            // The maximum length of a Short Code (aka Short String) is 2
+            if (dialString.length() <= MAX_LENGTH_SHORT_CODE) {
+                if (dialString.charAt(dialString.length() - 1) == END_OF_USSD_COMMAND) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
index 206e62f..e8d10f9 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
@@ -81,6 +81,7 @@
         case EF_SPN_CPHS:
         case EF_SPN_SHORT_CPHS:
         case EF_INFO_CPHS:
+        case EF_CSP_CPHS:
             return MF_SIM + DF_GSM;
 
         case EF_PBR:
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index b14896a..438996f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -73,6 +73,7 @@
      *  mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table
      */
     private byte[] mCphsInfo = null;
+    boolean mCspPlmnEnabled = true;
 
     byte[] efMWIS = null;
     byte[] efCPHS_MWI =null;
@@ -93,6 +94,7 @@
     static final int SPN_RULE_SHOW_PLMN = 0x02;
 
     // From TS 51.011 EF[SPDI] section
+    static final int TAG_SPDI = 0xA3;
     static final int TAG_SPDI_PLMN_LIST = 0x80;
 
     // Full Name IEI from TS 24.008
@@ -140,6 +142,7 @@
     private static final int EVENT_SET_MSISDN_DONE = 30;
     private static final int EVENT_SIM_REFRESH = 31;
     private static final int EVENT_GET_CFIS_DONE = 32;
+    private static final int EVENT_GET_CSP_CPHS_DONE = 33;
 
     // ***** Constructor
 
@@ -559,6 +562,13 @@
                 break;
             case EVENT_GET_CPHS_MAILBOX_DONE:
             case EVENT_GET_MBDN_DONE:
+                //Resetting the voice mail number and voice mail tag to null
+                //as these should be updated from the data read from EF_MBDN.
+                //If they are not reset, incase of invalid data/exception these
+                //variables are retaining their previous values and are
+                //causing invalid voice mailbox info display to user.
+                voiceMailNum = null;
+                voiceMailTag = null;
                 isRecordLoadResponse = true;
 
                 ar = (AsyncResult)msg.obj;
@@ -994,6 +1004,22 @@
                 ((GSMPhone) phone).notifyCallForwardingIndicator();
                 break;
 
+            case EVENT_GET_CSP_CPHS_DONE:
+                isRecordLoadResponse = true;
+
+                ar = (AsyncResult)msg.obj;
+
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG,"Exception in fetching EF_CSP data " + ar.exception);
+                    break;
+                }
+
+                data = (byte[])ar.result;
+
+                Log.i(LOG_TAG,"EF_CSP: " + IccUtils.bytesToHexString(data));
+                handleEfCspData(data);
+                break;
+
         }}catch (RuntimeException exc) {
             // I don't want these exceptions to be fatal
             Log.w(LOG_TAG, "Exception parsing SIM record", exc);
@@ -1017,6 +1043,12 @@
                 new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
                 break;
+            case EF_CSP_CPHS:
+                recordsToLoad++;
+                Log.i(LOG_TAG, "[CSP] SIM Refresh for EF_CSP_CPHS");
+                phone.getIccFileHandler().loadEFTransparent(EF_CSP_CPHS,
+                        obtainMessage(EVENT_GET_CSP_CPHS_DONE));
+                break;
             default:
                 // For now, fetch all records if this is not a
                 // voicemail number.
@@ -1247,6 +1279,9 @@
         iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
         recordsToLoad++;
 
+        iccFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
+        recordsToLoad++;
+
         // XXX should seek instead of examining them all
         if (false) { // XXX
             iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
@@ -1426,8 +1461,12 @@
 
         byte[] plmnEntries = null;
 
-        // There should only be one TAG_SPDI_PLMN_LIST
         for ( ; tlv.isValidObject() ; tlv.nextObject()) {
+            // Skip SPDI tag, if existant
+            if (tlv.getTag() == TAG_SPDI) {
+              tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
+            }
+            // There should only be one TAG_SPDI_PLMN_LIST
             if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
                 plmnEntries = tlv.getData();
                 break;
@@ -1464,4 +1503,53 @@
         Log.d(LOG_TAG, "[SIMRecords] " + s);
     }
 
+    /**
+     * Return true if "Restriction of menu options for manual PLMN selection"
+     * bit is set or EF_CSP data is unavailable, return false otherwise.
+     */
+    public boolean isCspPlmnEnabled() {
+        return mCspPlmnEnabled;
+    }
+
+    /**
+     * Parse EF_CSP data and check if
+     * "Restriction of menu options for manual PLMN selection" is
+     * Enabled/Disabled
+     *
+     * @param data EF_CSP hex data.
+     */
+    private void handleEfCspData(byte[] data) {
+        // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
+        // 18 bytes (i.e 9 service groups info) and additional data specific to
+        // operator. The valueAddedServicesGroup is not part of standard
+        // services. This is operator specific and can be programmed any where.
+        // Normally this is programmed as 10th service after the standard
+        // services.
+        int usedCspGroups = data.length / 2;
+        // This is the "Servive Group Number" of "Value Added Services Group".
+        byte valueAddedServicesGroup = (byte)0xC0;
+
+        mCspPlmnEnabled = true;
+        for (int i = 0; i < usedCspGroups; i++) {
+             if (data[2 * i] == valueAddedServicesGroup) {
+                 Log.i(LOG_TAG, "[CSP] found ValueAddedServicesGroup, value "
+                       + data[(2 * i) + 1]);
+                 if ((data[(2 * i) + 1] & 0x80) == 0x80) {
+                     // Bit 8 is for
+                     // "Restriction of menu options for manual PLMN selection".
+                     // Operator Selection menu should be enabled.
+                     mCspPlmnEnabled = true;
+                 } else {
+                     mCspPlmnEnabled = false;
+                     // Operator Selection menu should be disabled.
+                     // Operator Selection Mode should be set to Automatic.
+                     Log.i(LOG_TAG,"[CSP] Set Automatic Network Selection");
+                     phone.setNetworkSelectionModeAutomatic(null);
+                 }
+                 return;
+             }
+        }
+
+        Log.w(LOG_TAG, "[CSP] Value Added Service Group (0xC0), not found!");
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 50dd402..9a3c476 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -930,6 +930,8 @@
         // TP-Message-Type-Indicator
         // 9.2.3
         case 0:
+        case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved.
+                //This should be processed in the same way as MTI == 0 (Deliver)
             parseSmsDeliver(p, firstByte);
             break;
         case 2:
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
old mode 100644
new mode 100755
index 41e527c..b642541
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -53,6 +53,7 @@
     private ArrayList<byte[]> mIapFileRecord;
     private ArrayList<byte[]> mEmailFileRecord;
     private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
+    private boolean mRefreshCache = false;
 
     private static final int EVENT_PBR_LOAD_DONE = 1;
     private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
@@ -91,11 +92,19 @@
         mEmailFileRecord = null;
         mPbrFile = null;
         mIsPbrPresent = true;
+        mRefreshCache = false;
     }
 
     public ArrayList<AdnRecord> loadEfFilesFromUsim() {
         synchronized (mLock) {
-            if (!mPhoneBookRecords.isEmpty()) return mPhoneBookRecords;
+            if (!mPhoneBookRecords.isEmpty()) {
+                if (mRefreshCache) {
+                    mRefreshCache = false;
+                    refreshCache();
+                }
+                return mPhoneBookRecords;
+            }
+
             if (!mIsPbrPresent) return null;
 
             // Check if the PBR file is present in the cache, if not read it
@@ -116,6 +125,20 @@
         return mPhoneBookRecords;
     }
 
+    private void refreshCache() {
+        if (mPbrFile == null) return;
+        mPhoneBookRecords.clear();
+
+        int numRecs = mPbrFile.mFileIds.size();
+        for (int i = 0; i < numRecs; i++) {
+            readAdnFileAndWait(i);
+        }
+    }
+
+    public void invalidateCache() {
+        mRefreshCache = true;
+    }
+
     private void readPbrFileAndWait() {
         mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
         try {
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/package.html b/telephony/java/com/android/internal/telephony/gsm/stk/package.html
deleted file mode 100644
index c285b57..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/stk/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-Provides classes for SIM Toolkit Service.
-</BODY>
-</HTML>
diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
index de59b81..67df510 100644
--- a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony;
+package android.telephony;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java
index 88eaecd..4c7ebca 100644
--- a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java
+++ b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony;
+package android.telephony;
 
 import android.telephony.PhoneNumberFormattingTextWatcher;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/Wap230WspContentTypeTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/Wap230WspContentTypeTest.java
new file mode 100644
index 0000000..d31b294
--- /dev/null
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/Wap230WspContentTypeTest.java
@@ -0,0 +1,853 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.WspTypeDecoder;
+import com.android.internal.util.HexDump;
+
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+public class Wap230WspContentTypeTest extends TestCase {
+
+    public static final Map<Integer, String> WELL_KNOWN_SHORT_MIME_TYPES
+            = new HashMap<Integer, String>();
+    public static final Map<Integer, String> WELL_KNOWN_LONG_MIME_TYPES
+            = new HashMap<Integer, String>();
+    public static final Map<Integer, String> WELL_KNOWN_PARAMETERS
+            = new HashMap<Integer, String>();
+
+    static {
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x00, "*/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x01, "text/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x02, "text/html");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x03, "text/plain");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x04, "text/x-hdml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x05, "text/x-ttml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x06, "text/x-vCalendar");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x07, "text/x-vCard");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x08, "text/vnd.wap.wml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x09, "text/vnd.wap.wmlscript");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x0A, "text/vnd.wap.wta-event");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x0B, "multipart/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x0C, "multipart/mixed");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x0D, "multipart/form-data");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x0E, "multipart/byterantes");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x0F, "multipart/alternative");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x10, "application/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x11, "application/java-vm");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x12, "application/x-www-form-urlencoded");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x13, "application/x-hdmlc");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x14, "application/vnd.wap.wmlc");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x15, "application/vnd.wap.wmlscriptc");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x16, "application/vnd.wap.wta-eventc");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x17, "application/vnd.wap.uaprof");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x18, "application/vnd.wap.wtls-ca-certificate");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x19, "application/vnd.wap.wtls-user-certificate");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x1A, "application/x-x509-ca-cert");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x1B, "application/x-x509-user-cert");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x1C, "image/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x1D, "image/gif");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x1E, "image/jpeg");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x1F, "image/tiff");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x20, "image/png");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x21, "image/vnd.wap.wbmp");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x22, "application/vnd.wap.multipart.*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x23, "application/vnd.wap.multipart.mixed");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x24, "application/vnd.wap.multipart.form-data");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x25, "application/vnd.wap.multipart.byteranges");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x26, "application/vnd.wap.multipart.alternative");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x27, "application/xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x28, "text/xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x29, "application/vnd.wap.wbxml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x2A, "application/x-x968-cross-cert");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x2B, "application/x-x968-ca-cert");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x2C, "application/x-x968-user-cert");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x2D, "text/vnd.wap.si");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x2E, "application/vnd.wap.sic");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x2F, "text/vnd.wap.sl");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x30, "application/vnd.wap.slc");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x31, "text/vnd.wap.co");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x32, "application/vnd.wap.coc");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x33, "application/vnd.wap.multipart.related");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x34, "application/vnd.wap.sia");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x35, "text/vnd.wap.connectivity-xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x36, "application/vnd.wap.connectivity-wbxml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x37, "application/pkcs7-mime");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x38, "application/vnd.wap.hashed-certificate");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x39, "application/vnd.wap.signed-certificate");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x3A, "application/vnd.wap.cert-response");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x3B, "application/xhtml+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x3C, "application/wml+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x3D, "text/css");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x3E, "application/vnd.wap.mms-message");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x3F, "application/vnd.wap.rollover-certificate");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x40, "application/vnd.wap.locc+wbxml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x41, "application/vnd.wap.loc+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x42, "application/vnd.syncml.dm+wbxml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x43, "application/vnd.syncml.dm+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x44, "application/vnd.syncml.notification");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x45, "application/vnd.wap.xhtml+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x46, "application/vnd.wv.csp.cir");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x47, "application/vnd.oma.dd+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x48, "application/vnd.oma.drm.message");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x49, "application/vnd.oma.drm.content");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x4A, "application/vnd.oma.drm.rights+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x4B, "application/vnd.oma.drm.rights+wbxml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x4C, "application/vnd.wv.csp+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x4D, "application/vnd.wv.csp+wbxml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x4E, "application/vnd.syncml.ds.notification");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x4F, "audio/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x50, "video/*");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x51, "application/vnd.oma.dd2+xml");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x52, "application/mikey");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x53, "application/vnd.oma.dcd");
+        WELL_KNOWN_SHORT_MIME_TYPES.put(0x54, "application/vnd.oma.dcdc");
+
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0201, "application/vnd.uplanet.cacheop-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0202, "application/vnd.uplanet.signal");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0203, "application/vnd.uplanet.alert-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0204, "application/vnd.uplanet.list-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0205, "application/vnd.uplanet.listcmd-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0206, "application/vnd.uplanet.channel-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0207, "application/vnd.uplanet.provisioning-status-uri");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0208, "x-wap.multipart/vnd.uplanet.header-set");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0209, "application/vnd.uplanet.bearer-choice-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x020A, "application/vnd.phonecom.mmc-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x020B, "application/vnd.nokia.syncset+wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x020C, "image/x-up-wpng");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0300, "application/iota.mmc-wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0301, "application/iota.mmc-xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0302, "application/vnd.syncml+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0303, "application/vnd.syncml+wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0304, "text/vnd.wap.emn+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0305, "text/calendar");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0306, "application/vnd.omads-email+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0307, "application/vnd.omads-file+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0308, "application/vnd.omads-folder+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0309, "text/directory;profile=vCard");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x030A, "application/vnd.wap.emn+wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x030B, "application/vnd.nokia.ipdc-purchase-response");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x030C, "application/vnd.motorola.screen3+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x030D, "application/vnd.motorola.screen3+gzip");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x030E, "application/vnd.cmcc.setting+wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x030F, "application/vnd.cmcc.bombing+wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0310, "application/vnd.docomo.pf");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0311, "application/vnd.docomo.ub");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0312, "application/vnd.omaloc-supl-init");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0313, "application/vnd.oma.group-usage-list+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0314, "application/oma-directory+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0315, "application/vnd.docomo.pf2");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0316, "application/vnd.oma.drm.roap-trigger+wbxml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0317, "application/vnd.sbm.mid2");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0318, "application/vnd.wmf.bootstrap");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x0319, "application/vnc.cmcc.dcd+xml");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x031A, "application/vnd.sbm.cid");
+        WELL_KNOWN_LONG_MIME_TYPES.put(0x031B, "application/vnd.oma.bcast.provisioningtrigger");
+
+        WELL_KNOWN_PARAMETERS.put(0x00, "Q");
+        WELL_KNOWN_PARAMETERS.put(0x01, "Charset");
+        WELL_KNOWN_PARAMETERS.put(0x02, "Level");
+        WELL_KNOWN_PARAMETERS.put(0x03, "Type");
+        WELL_KNOWN_PARAMETERS.put(0x07, "Differences");
+        WELL_KNOWN_PARAMETERS.put(0x08, "Padding");
+        WELL_KNOWN_PARAMETERS.put(0x09, "Type");
+        WELL_KNOWN_PARAMETERS.put(0x0E, "Max-Age");
+        WELL_KNOWN_PARAMETERS.put(0x10, "Secure");
+        WELL_KNOWN_PARAMETERS.put(0x11, "SEC");
+        WELL_KNOWN_PARAMETERS.put(0x12, "MAC");
+        WELL_KNOWN_PARAMETERS.put(0x13, "Creation-date");
+        WELL_KNOWN_PARAMETERS.put(0x14, "Modification-date");
+        WELL_KNOWN_PARAMETERS.put(0x15, "Read-date");
+        WELL_KNOWN_PARAMETERS.put(0x16, "Size");
+        WELL_KNOWN_PARAMETERS.put(0x17, "Name");
+        WELL_KNOWN_PARAMETERS.put(0x18, "Filename");
+        WELL_KNOWN_PARAMETERS.put(0x19, "Start");
+        WELL_KNOWN_PARAMETERS.put(0x1A, "Start-info");
+        WELL_KNOWN_PARAMETERS.put(0x1B, "Comment");
+        WELL_KNOWN_PARAMETERS.put(0x1C, "Domain");
+        WELL_KNOWN_PARAMETERS.put(0x1D, "Path");
+
+    }
+
+    final int WSP_DEFINED_SHORT_MIME_TYPE_COUNT = 85;
+    final int WSP_DEFINED_LONG_MIME_TYPE_COUNT = 85;
+
+    private static final byte WSP_STRING_TERMINATOR = 0x00;
+    private static final byte WSP_SHORT_INTEGER_MASK = (byte) 0x80;
+    private static final byte WSP_LENGTH_QUOTE = 0x1F;
+    private static final byte WSP_QUOTE = 0x22;
+
+    private static final short LONG_MIME_TYPE_OMA_DIRECTORY_XML = 0x0314;
+    private static final short LONG_MIME_TYPE_UNASSIGNED = 0x052C;
+
+    private static final byte SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE = 0x3F;
+    private static final byte SHORT_MIME_TYPE_UNASSIGNED = 0x60;
+
+    private static final String STRING_MIME_TYPE_ROLLOVER_CERTIFICATE
+            = "application/vnd.wap.rollover-certificate";
+
+    private static final byte TYPED_PARAM_Q = 0x00;
+    private static final byte TYPED_PARAM_DOMAIN = 0x1C;
+    private static final byte PARAM_UNASSIGNED = 0x42;
+    private static final byte PARAM_NO_VALUE = 0x00;
+    private static final byte TYPED_PARAM_SEC = 0x11;
+    private static final byte TYPED_PARAM_MAC = 0x12;
+
+    public void testHasExpectedNumberOfShortMimeTypes() {
+        assertEquals(WSP_DEFINED_SHORT_MIME_TYPE_COUNT, WELL_KNOWN_SHORT_MIME_TYPES.size());
+    }
+
+    public void testHasExpectedNumberOfLongMimeTypes() {
+        assertEquals(WSP_DEFINED_LONG_MIME_TYPE_COUNT, WELL_KNOWN_LONG_MIME_TYPES.size());
+    }
+
+    public void testWellKnownShortIntegerMimeTypeValues() {
+
+        for (int value : Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.keySet()) {
+            WspTypeDecoder unit = new WspTypeDecoder(
+                    HexDump.toByteArray((byte) (value | WSP_SHORT_INTEGER_MASK)));
+            assertTrue(unit.decodeContentType(0));
+            String mimeType = unit.getValueString();
+            int wellKnownValue = (int) unit.getValue32();
+            assertEquals(Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.get(value), mimeType);
+            assertEquals(value, wellKnownValue);
+            assertEquals(1, unit.getDecodedDataLength());
+        }
+    }
+
+    public void testWellKnownLongIntegerMimeTypeValues() {
+        byte headerLength = 3;
+        byte typeLength = 2;
+        for (int value : Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.keySet()) {
+            byte[] data = new byte[10];
+            data[0] = headerLength;
+            data[1] = typeLength;
+            data[2] = (byte) (value >> 8);
+            data[3] = (byte) (value & 0xFF);
+            WspTypeDecoder unit = new WspTypeDecoder(data);
+            assertTrue(unit.decodeContentType(0));
+            String mimeType = unit.getValueString();
+            int wellKnownValue = (int) unit.getValue32();
+            assertEquals(Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.get(value), mimeType);
+            assertEquals(value, wellKnownValue);
+            assertEquals(4, unit.getDecodedDataLength());
+        }
+    }
+
+    public void testDecodeReturnsFalse_WhenOnlyAZeroBytePresent() {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x00);
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertFalse(unit.decodeContentType(0));
+    }
+
+    public void testConstrainedMediaExtensionMedia() throws Exception {
+
+        String testType = "application/wibble";
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(testType.getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+        String mimeType = unit.getValueString();
+        assertEquals(testType, mimeType);
+        assertEquals(-1, unit.getValue32());
+        assertEquals(19, unit.getDecodedDataLength());
+    }
+
+    public void testGeneralFormShortLengthExtensionMedia() throws Exception {
+
+        String testType = "12345678901234567890123456789";
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(testType.length() + 1);
+        out.write(testType.getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+        assertEquals(testType, mimeType);
+        assertEquals(-1, unit.getValue32());
+        assertEquals(31, unit.getDecodedDataLength());
+    }
+
+    public void testGeneralFormShortLengthWellKnownShortInteger()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x01);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(2, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormShortLengthWellKnownShortIntegerWithUnknownValue()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x01);
+        out.write(SHORT_MIME_TYPE_UNASSIGNED | WSP_SHORT_INTEGER_MASK);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+        assertNull(mimeType);
+        assertEquals(SHORT_MIME_TYPE_UNASSIGNED, unit.getValue32());
+        assertEquals(2, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormShortLengthWellKnownLongInteger()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(0x03); // header length
+        out.write(0x02); // type length (2 octets)
+        out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML >> 8);
+        out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML & 0xFF);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals("application/oma-directory+xml", mimeType);
+        assertEquals(LONG_MIME_TYPE_OMA_DIRECTORY_XML, unit.getValue32());
+        assertEquals(4, unit.getDecodedDataLength());
+    }
+
+    public void testGeneralFormShortLengthWellKnownLongIntegerWithUnknownValue()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(0x03); // Value-length, short-length
+        out.write(0x02); // long-integer length (2 octets)
+        out.write(LONG_MIME_TYPE_UNASSIGNED >> 8);
+        out.write(LONG_MIME_TYPE_UNASSIGNED & 0xFF);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertNull(mimeType);
+        assertEquals(LONG_MIME_TYPE_UNASSIGNED, unit.getValue32());
+        assertEquals(4, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormLengthQuoteWellKnownShortInteger()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(WSP_LENGTH_QUOTE);
+        out.write(0x01); // Length as UINTVAR
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(3, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormLengthQuoteWellKnownShortIntegerWithUnknownValue()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(WSP_LENGTH_QUOTE);
+        out.write(0x01); // Length as UINTVAR
+        out.write(SHORT_MIME_TYPE_UNASSIGNED | WSP_SHORT_INTEGER_MASK);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+        assertNull(mimeType);
+        assertEquals(SHORT_MIME_TYPE_UNASSIGNED, unit.getValue32());
+        assertEquals(3, unit.getDecodedDataLength());
+    }
+
+    public void testGeneralFormLengthQuoteWellKnownLongInteger()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(WSP_LENGTH_QUOTE);
+        out.write(0x03); // Length as UINTVAR
+        out.write(0x02); // long-integer length (2 octets)
+        out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML >> 8);
+        out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML & 0xFF);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals("application/oma-directory+xml", mimeType);
+        assertEquals(LONG_MIME_TYPE_OMA_DIRECTORY_XML, unit.getValue32());
+        assertEquals(5, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormLengthQuoteWellKnownLongIntegerWithUnknownValue()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(WSP_LENGTH_QUOTE);
+        out.write(0x03); // Length as UINTVAR
+        out.write(0x02); // long-integer length (2 octets)
+        out.write(LONG_MIME_TYPE_UNASSIGNED >> 8);
+        out.write(LONG_MIME_TYPE_UNASSIGNED & 0xFF);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertNull(mimeType);
+        assertEquals(LONG_MIME_TYPE_UNASSIGNED, unit.getValue32());
+        assertEquals(5, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormLengthQuoteExtensionMedia() throws Exception {
+
+        String testType = "application/wibble";
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(WSP_LENGTH_QUOTE);
+        out.write(testType.length() + 1); // Length as UINTVAR
+
+        out.write(testType.getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(testType, mimeType);
+        assertEquals(-1, unit.getValue32());
+        assertEquals(21, unit.getDecodedDataLength());
+
+    }
+
+    public void testGeneralFormLengthQuoteExtensionMediaWithNiceLongMimeType() throws Exception {
+
+        String testType =
+                "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
+                +"01234567890123456789012345678901234567890123456789012345678901234567890123456789";
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        out.write(WSP_LENGTH_QUOTE);
+        out.write(0x81); // Length as UINTVAR (161 decimal, 0xA1), 2 bytes
+        out.write(0x21);
+
+        out.write(testType.getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(testType, mimeType);
+        assertEquals(-1, unit.getValue32());
+        assertEquals(164, unit.getDecodedDataLength());
+
+    }
+
+    public void testConstrainedMediaExtensionMediaWithSpace() throws Exception {
+
+        String testType = " application/wibble";
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(testType.getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(testType, mimeType);
+        assertEquals(-1, unit.getValue32());
+        assertEquals(20, unit.getDecodedDataLength());
+
+    }
+
+    public void testTypedParamWellKnownShortIntegerNoValue()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x03); // Value-length, short-length
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_DOMAIN | WSP_SHORT_INTEGER_MASK);
+        out.write(PARAM_NO_VALUE);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+
+        assertEquals(4, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals(null, params.get("Domain"));
+
+    }
+
+    public void testTypedParamWellKnownShortIntegerTokenText() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x14); // Value-length, short-length
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_DOMAIN | WSP_SHORT_INTEGER_MASK);
+        out.write("wdstechnology.com".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+
+        assertEquals(out.toByteArray().length, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("wdstechnology.com", params.get("Domain"));
+
+    }
+
+    public void testTypedParamWellKnownLongIntegerTokenText() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x15);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(0x01);
+        out.write(TYPED_PARAM_DOMAIN);
+        out.write("wdstechnology.com".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+
+        assertEquals(22, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("wdstechnology.com", params.get("Domain"));
+
+    }
+
+    public void testTypedParamWellKnownShortIntegerQuotedText() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x15);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_DOMAIN | WSP_SHORT_INTEGER_MASK);
+        out.write(WSP_QUOTE);
+        out.write("wdstechnology.com".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(0x3F, unit.getValue32());
+        assertEquals(22, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("wdstechnology.com", params.get("Domain"));
+
+    }
+
+    public void testTypedParamWellKnownShortIntegerCompactIntegerValue()  {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x3);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_SEC | WSP_SHORT_INTEGER_MASK);
+        out.write(0x01 | WSP_SHORT_INTEGER_MASK);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(0x3F, unit.getValue32());
+        assertEquals(4, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("1", params.get("SEC"));
+
+    }
+
+    public void testTypedParamWellKnownShortIntegerMultipleParameters() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x0B);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_SEC | WSP_SHORT_INTEGER_MASK);
+        out.write(0x01 | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_MAC | WSP_SHORT_INTEGER_MASK);
+        out.write(WSP_QUOTE);
+        out.write("imapc".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(12, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("1", params.get("SEC"));
+        assertEquals("imapc", params.get("MAC"));
+    }
+
+    public void testUntypedParamIntegerValueShortInteger() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x0A);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write("MYPARAM".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR); // EOS
+        out.write(0x45 | WSP_SHORT_INTEGER_MASK);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(11, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("69", params.get("MYPARAM"));
+    }
+
+    public void testUntypedParamIntegerValueLongInteger() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x0C);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write("MYPARAM".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+        out.write(0x02); // Short Length
+        out.write(0x42); // Long Integer byte 1
+        out.write(0x69); // Long Integer byte 2
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(0x3F, unit.getValue32());
+        assertEquals(13, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("17001", params.get("MYPARAM"));
+    }
+
+    public void testUntypedParamTextNoValue() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x0A);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write("MYPARAM".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+        out.write(PARAM_NO_VALUE);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(11, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals(null, params.get("MYPARAM"));
+
+    }
+
+    public void testUntypedParamTextTokenText() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x11);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write("MYPARAM".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+        out.write("myvalue".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(18, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("myvalue", params.get("MYPARAM"));
+    }
+
+    public void testUntypedParamTextQuotedString() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x11);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write("MYPARAM".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+        out.write(WSP_QUOTE);
+        out.write("myvalue".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+        assertEquals(19, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("myvalue", params.get("MYPARAM"));
+
+    }
+
+    public void testDecodesReturnsFalse_ForParamWithMissingValue() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x09);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write("MYPARAM".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertFalse(unit.decodeContentType(0));
+    }
+
+    public void testTypedParamTextQValue()  {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x04);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(TYPED_PARAM_Q);
+        out.write(0x83); // Q value byte 1
+        out.write(0x31); // Q value byte 2
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(0x3F, unit.getValue32());
+        assertEquals(5, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("433", params.get("Q"));
+
+    }
+
+    public void testTypedParamUnassignedWellKnownShortIntegerTokenText() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x14);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(PARAM_UNASSIGNED | WSP_SHORT_INTEGER_MASK);
+        out.write("wdstechnology.com".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+
+        assertEquals(21, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("wdstechnology.com", params.get("unassigned/0x42"));
+
+    }
+
+    public void testTypedParamUnassignedWellKnownLongIntegerTokenText() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x15);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(0x01); // Short-length of well-known parameter token
+        out.write(PARAM_UNASSIGNED);
+        out.write("wdstechnology.com".getBytes("US-ASCII"));
+        out.write(WSP_STRING_TERMINATOR);
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertTrue(unit.decodeContentType(0));
+
+        String mimeType = unit.getValueString();
+
+        assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType);
+        assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32());
+
+        assertEquals(22, unit.getDecodedDataLength());
+
+        Map<String, String> params = unit.getContentParameters();
+        assertEquals("wdstechnology.com", params.get("unassigned/0x42"));
+    }
+
+    public void testDecodesReturnsFalse_WhenParamValueNotTerminated() throws Exception {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(0x15);
+        out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK);
+        out.write(0x01);
+        out.write(PARAM_UNASSIGNED);
+        out.write("wdstechnology.com".getBytes("US-ASCII"));
+
+        WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray());
+        assertFalse(unit.decodeContentType(0));
+    }
+}
\ No newline at end of file
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
index f02673c..8331f0c 100644
--- a/tests/CoreTests/android/AndroidManifest.xml
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -24,6 +24,7 @@
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
     <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
     <!-- location test permissions -->
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/tests/CoreTests/android/core/HttpHeaderTest.java b/tests/CoreTests/android/core/HttpHeaderTest.java
new file mode 100644
index 0000000..a5d48578
--- /dev/null
+++ b/tests/CoreTests/android/core/HttpHeaderTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.core;
+
+import android.test.AndroidTestCase;
+import org.apache.http.util.CharArrayBuffer;
+
+import android.net.http.Headers;
+
+public class HttpHeaderTest extends AndroidTestCase {
+
+    static final String LAST_MODIFIED = "Last-Modified: Fri, 18 Jun 2010 09:56:47 GMT";
+    static final String CACHE_CONTROL_MAX_AGE = "Cache-Control:max-age=15";
+    static final String CACHE_CONTROL_PRIVATE = "Cache-Control: private";
+
+    /**
+     * Tests that cache control header supports multiple instances of the header,
+     * according to HTTP specification.
+     *
+     * The HTTP specification states the following about the fields:
+     * Multiple message-header fields with the same field-name MAY be present
+     * in a message if and only if the entire field-value for that header field
+     * is defined as a comma-separated list [i.e., #(values)]. It MUST be
+     * possible to combine the multiple header fields into one "field-name:
+     * field-value" pair, without changing the semantics of the message, by
+     * appending each subsequent field-value to the first, each separated by a
+     * comma. The order in which header fields with the same field-name are
+     * received is therefore significant to the interpretation of the combined
+     * field value, and thus a proxy MUST NOT change the order of these field
+     * values when a message is forwarded.
+     */
+    public void testCacheControl() throws Exception {
+        Headers h = new Headers();
+        CharArrayBuffer buffer = new CharArrayBuffer(64);
+
+        buffer.append(CACHE_CONTROL_MAX_AGE);
+        h.parseHeader(buffer);
+
+        buffer.clear();
+        buffer.append(LAST_MODIFIED);
+        h.parseHeader(buffer);
+        assertEquals("max-age=15", h.getCacheControl());
+
+        buffer.clear();
+        buffer.append(CACHE_CONTROL_PRIVATE);
+        h.parseHeader(buffer);
+        assertEquals("max-age=15,private", h.getCacheControl());
+    }
+}
diff --git a/tests/CoreTests/android/core/ProxyTest.java b/tests/CoreTests/android/core/ProxyTest.java
new file mode 100644
index 0000000..12acfe8
--- /dev/null
+++ b/tests/CoreTests/android/core/ProxyTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import org.apache.http.HttpHost;
+
+import android.content.Context;
+import android.net.Proxy;
+import android.test.AndroidTestCase;
+
+/**
+ * Proxy tests
+ */
+public class ProxyTest extends AndroidTestCase {
+    private Context mContext;
+    private HttpHost mHttpHost;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = getContext();
+        mHttpHost = null;
+        String proxyHost = Proxy.getHost(mContext);
+        int proxyPort = Proxy.getPort(mContext);
+        if (proxyHost != null) {
+            mHttpHost = new HttpHost(proxyHost, proxyPort, "http");
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Bad url parameter should not cause any exception.
+     */
+    public void testProxyGetPreferredHttpHost_UrlBad() throws Exception {
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, null));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, ""));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad:"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad:\\"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad://#"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "://#"));
+    }
+
+    /**
+     * Proxy (if available) should be returned when url parameter is not localhost.
+     */
+    public void testProxyGetPreferredHttpHost_UrlNotlLocalhost() throws Exception {
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://example.com"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://example.com/"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://192.168.0.1/"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "file:///foo/bar"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "rtsp://example.com"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "rtsp://example.com/"));
+        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "javascript:alert(1)"));
+    }
+
+    /**
+     * No proxy should be returned when url parameter is localhost.
+     */
+    public void testProxyGetPreferredHttpHost_UrlLocalhost() throws Exception {
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost/"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost/hej.html"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1/"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1/hej.html"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1:80/"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1:8080/"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "rtsp://127.0.0.1/"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "rtsp://localhost/"));
+        assertNull(Proxy.getPreferredHttpHost(mContext, "https://localhost/"));
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
index e741177..73d7363 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
@@ -31,6 +31,7 @@
 import android.widget.ListView;
 import android.widget.SimpleAdapter;
 import android.os.Bundle;
+import android.os.Environment;
 
 
 public abstract class FileList extends ListActivity
@@ -179,10 +180,9 @@
         getListView().setSelection(mFocusIndex);
     }
 
-    protected void setupPath()
-    {
-    	mPath = "/sdcard/android/layout_tests";
-    	mBaseLength = mPath.length();
+    protected void setupPath() {
+        mPath = Environment.getExternalStorageDirectory() + "/android/layout_tests";
+        mBaseLength = mPath.length();
     }
 
     protected String mPath;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 322b0d2..6cfce41 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -18,6 +18,7 @@
 
 import com.android.dumprendertree.forwarder.ForwardService;
 
+import android.os.Environment;
 import android.util.Log;
 
 import java.io.BufferedOutputStream;
@@ -32,11 +33,17 @@
 public class FsUtils {
 
     private static final String LOGTAG = "FsUtils";
-    static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
-    static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
-    static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
-    static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
-    static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+    static final String EXTERNAL_DIR = Environment.getExternalStorageDirectory().toString();
+    static final String HTTP_TESTS_PREFIX =
+        EXTERNAL_DIR + "/android/layout_tests/http/tests/";
+    static final String HTTPS_TESTS_PREFIX =
+        EXTERNAL_DIR + "/android/layout_tests/http/tests/ssl/";
+    static final String HTTP_LOCAL_TESTS_PREFIX =
+        EXTERNAL_DIR + "/android/layout_tests/http/tests/local/";
+    static final String HTTP_MEDIA_TESTS_PREFIX =
+        EXTERNAL_DIR + "/android/layout_tests/http/tests/media/";
+    static final String HTTP_WML_TESTS_PREFIX =
+        EXTERNAL_DIR + "/android/layout_tests/http/tests/wml/";
 
     private FsUtils() {
         //no creation of instances
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 042158a..9ccf549 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -18,12 +18,12 @@
 
 import com.android.dumprendertree.TestShellActivity.DumpDataType;
 import com.android.dumprendertree.forwarder.AdbUtils;
-import com.android.dumprendertree.forwarder.ForwardServer;
 import com.android.dumprendertree.forwarder.ForwardService;
 
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Environment;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
@@ -92,10 +92,11 @@
 
     public MyTestRecorder(boolean resume) {
         try {
-            File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
-            File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
-            File resultsIgnoreResultFile = new File("/sdcard/layout_tests_ignored.txt");
-            File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
+            File externalDir = Environment.getExternalStorageDirectory();
+            File resultsPassedFile = new File(externalDir, "layout_tests_passed.txt");
+            File resultsFailedFile = new File(externalDir, "layout_tests_failed.txt");
+            File resultsIgnoreResultFile = new File(externalDir, "layout_tests_ignored.txt");
+            File noExpectedResultFile = new File(externalDir, "layout_tests_nontext.txt");
 
             mBufferedOutputPassedStream =
                 new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
@@ -128,11 +129,12 @@
     private static final String LOGTAG = "LayoutTests";
     static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
 
-    static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
-    static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
-    static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
-    static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/android/layout_tests_list.txt";
-    static final String TEST_STATUS_FILE = "/sdcard/android/running_test.txt";
+    static final String EXTERNAL_DIR = Environment.getExternalStorageDirectory().toString();
+    static final String LAYOUT_TESTS_ROOT = EXTERNAL_DIR + "/android/layout_tests/";
+    static final String LAYOUT_TESTS_RESULT_DIR = EXTERNAL_DIR + "/android/layout_tests_results/";
+    static final String ANDROID_EXPECTED_RESULT_DIR = EXTERNAL_DIR + "/android/expected_results/";
+    static final String LAYOUT_TESTS_LIST_FILE = EXTERNAL_DIR + "/android/layout_tests_list.txt";
+    static final String TEST_STATUS_FILE = EXTERNAL_DIR + "/android/running_test.txt";
     static final String LAYOUT_TESTS_RESULTS_REFERENCE_FILES[] = {
           "results/layout_tests_passed.txt",
           "results/layout_tests_failed.txt",
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index 2ef342f..9352f39 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Debug;
+import android.os.Environment;
 import android.os.Process;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
@@ -35,7 +36,8 @@
 public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
 
     private final static String LOGTAG = "LoadTest";
-    private final static String LOAD_TEST_RESULT = "/sdcard/load_test_result.txt";
+    private final static String LOAD_TEST_RESULT =
+        Environment.getExternalStorageDirectory() + "/load_test_result.txt";
     private boolean mFinished;
     static final String LOAD_TEST_RUNNER_FILES[] = {
         "run_page_cycler.py"
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
index 82671eb..9c4b57256 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Environment;
 import android.util.Log;
 
 import java.io.BufferedOutputStream;
@@ -28,7 +29,8 @@
 
     private static final int MENU_START = 0x01;
     private static String LOGTAG = "MenuActivity";
-    static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/android/layout_tests_list.txt";
+    static final String LAYOUT_TESTS_LIST_FILE =
+        Environment.getExternalStorageDirectory() + "/android/layout_tests_list.txt";
 
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
index 9bc0962..d146fc7 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
@@ -37,10 +38,16 @@
 
     private static final String LOGTAG = "ReliabilityTest";
     private static final String PKG_NAME = "com.android.dumprendertree";
-    private static final String TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt";
-    private static final String TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt";
-    private static final String TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt";
-    private static final String TEST_LOAD_TIME_FILE = "/sdcard/android/reliability_load_time.txt";
+    private static final String EXTERNAL_DIR =
+        Environment.getExternalStorageDirectory().toString();
+    private static final String TEST_LIST_FILE = EXTERNAL_DIR +
+        "/android/reliability_tests_list.txt";
+    private static final String TEST_STATUS_FILE = EXTERNAL_DIR +
+        "/android/reliability_running_test.txt";
+    private static final String TEST_TIMEOUT_FILE = EXTERNAL_DIR +
+        "/android/reliability_timeout_test.txt";
+    private static final String TEST_LOAD_TIME_FILE = EXTERNAL_DIR +
+        "/android/reliability_load_time.txt";
     private static final String TEST_DONE = "#DONE";
     static final String RELIABILITY_TEST_RUNNER_FILES[] = {
         "run_reliability_tests.py"
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 81d5b08..7475719 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -30,6 +30,7 @@
 import android.graphics.Bitmap.Config;
 import android.net.http.SslError;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
@@ -862,7 +863,8 @@
     static final String SAVE_IMAGE = "SaveImage";
 
     static final int DRAW_RUNS = 5;
-    static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt";
+    static final String DRAW_TIME_LOG = Environment.getExternalStorageDirectory() +
+        "/android/page_draw_time.txt";
 
     private boolean mGeolocationPermissionSet;
     private boolean mGeolocationPermission;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
index 8b7de6e..25dd04fd 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
@@ -21,6 +21,7 @@
 import java.io.FileReader;
 import java.io.IOException;
 
+import android.os.Environment;
 import android.util.Log;
 
 public class ForwardService {
@@ -33,7 +34,8 @@
 
     private static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com";
 
-    private static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt";
+    private static final String FORWARD_HOST_CONF =
+        Environment.getExternalStorageDirectory() + "/drt_forward_host.txt";
 
     private ForwardService() {
         int addr = getForwardHostAddr();
diff --git a/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java b/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java
index 98d0a50..4cfdf6c 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java
@@ -28,6 +28,7 @@
 import android.database.Cursor;
 import android.location.LocationManager;
 import android.os.Bundle;
+import android.os.Environment;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -210,12 +211,11 @@
     }
 
     private String getUniqueFileName(String ext) {
-        File dir = new File("/sdcard/locationtracker");
+        File dir = new File(Environment.getExternalStorageDirectory() + "/locationtracker");
         if (!dir.exists()) {
             dir.mkdir();
         }
-        return "/sdcard/locationtracker/tracking-" +
-            DateUtils.getCurrentTimestamp() + "." + ext;
+        return dir + "/tracking-" + DateUtils.getCurrentTimestamp() + "." + ext;
     }
 
     private void launchSettings() {
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index cfce7bd..b793d62 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -16,24 +16,19 @@
 
 package com.android.statusbartest;
 
-import android.app.ListActivity;
 import android.app.PendingIntent;
-import android.widget.ArrayAdapter;
-import android.view.View;
-import android.widget.ListView;
 import android.content.Context;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.os.Environment;
 import android.os.Vibrator;
-import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
 import android.net.Uri;
 import android.os.SystemClock;
 import android.widget.RemoteViews;
-import android.widget.TextView;
 import android.os.PowerManager;
 
 public class NotificationTestList extends TestActivity
@@ -70,7 +65,8 @@
                 pm.goToSleep(SystemClock.uptimeMillis());
 
                 Notification n = new Notification();
-                n.sound = Uri.parse("file:///sdcard/virtual-void.mp3");
+                n.sound = Uri.parse("file://" + Environment.getExternalStorageDirectory() +
+                        "/virtual-void.mp3");
                 Log.d(TAG, "n.sound=" + n.sound);
 
                 mNM.notify(1, n);
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 175a98b..70140d8 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -4,7 +4,7 @@
 	<classpathentry kind="src" path="tests"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/layoutlib_api"/>
+	<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
 	<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/>
 	<classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/layoutlib.jar" sourcepath="/ANDROID_SRC/frameworks/base/core/java"/>
 	<classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/ninepatch.jar" sourcepath="/ANDROID_SRC/development/tools/ninepatch/src"/>
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index b2010d5..b7a602a 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_JAVA_LIBRARIES := \
 	kxml2-2.3.0 \
-	layoutlib_api \
+	layoutlib_api-prebuilt \
 	ninepatch
 
 LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib
diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt
index 09b392b..c59e20d 100644
--- a/tools/layoutlib/create/README.txt
+++ b/tools/layoutlib/create/README.txt
@@ -4,68 +4,196 @@
 - Description -
 ---------------
 
-makeLayoutLib generates a library used by the Eclipse graphical layout editor
+Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor
 to perform layout.
 
 
-
 - Usage -
 ---------
 
- ./makeLayoutLib path/to/android.jar destination.jar
+ ./layoutlib_create path/to/android.jar destination.jar
+
+
+- Design Overview -
+-------------------
+
+Layoutlib_create uses the "android.jar" containing all the Java code used by Android
+as generated by the Android build, right before the classes are converted to a DEX format.
+
+The Android JAR can't be used directly in Eclipse:
+- it contains references to native code (which we want to avoid in Eclipse),
+- some classes need to be overridden, for example all the drawing code that is
+  replaced by Java 2D calls in Eclipse.
+- some of the classes that need to be changed are final and/or we need access
+  to their private internal state.
+
+Consequently this tool:
+- parses the input JAR,
+- modifies some of the classes directly using some bytecode manipulation,
+- filters some packages and removes some that we don't want to end in the output JAR,
+- injects some new classes,
+- and generates a modified JAR file that is suitable for the Android plugin
+  for Eclipse to perform rendering.
+
+The ASM library is used to do the bytecode modification using its visitor pattern API.
+
+The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the
+configuration is done in the main() method and the CreateInfo structure is expected to
+change with the Android platform as new classes are added, changed or removed.
+
+The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the
+platform, that provides all the necessary missing implementation for rendering graphics
+in Eclipse.
 
 
 
 - Implementation Notes -
 ------------------------
 
-The goal of makeLayoutLib is to list all the classes from the input jar and create a new
-jar that only keeps certain classes and create stubs for all their dependencies.
-
-First the input jar is parsed to find all the classes defined.
-
-In the Main(), the following list of classes are hardcoded (TODO config file later):
-- keep all classes that derive from android.view.View.
-- keep all classes in the android.view and android.widget packages (sub-packages excluded).
-- keep specific classes such as android.policy.PhoneLayoutInflater.
-
-For each class to keep, their dependencies are examined using BCEL.
-A dependency is defined as a class needed to instantiate the given class that should be kept,
-directly or indirectly. So a dependency is a class that is used by the input class, that is
-defined in the input jar and that is not part of the current JRE.
-
-Dependencies are computed recursively.
-
-Once all dependencies are found, the final jar can be created.
-There are three kind of classes to write:
-- classes that are to be kept as-is. They are just dumped in the new jar unchanged.
-- classes that are to be kept yet contain native methods or fields.
-- classes that are just dependencies. We don't want to expose their implementation in the final
-  jar.
-
-The implementation of native methods and all methods of mock classes is replaced by a stub
-that throws UnsupportedOperationException.
-
-Incidentally, the access level of native and mock classes needs to be changed in order for
-native methods to be later overridden. Methods that are "final private native" must become
-non-final, non-native and at most protected. Package-default access is changed to public.
-Classes that are final are made non-final. Abstract methods are left untouched.
+The tool works in two phases:
+- first analyze the input jar (AsmAnalyzer class)
+- then generate the output jar (AsmGenerator class),
 
 
+- Analyzer
+----------
 
-----
-20080617 Replace Class
+The goal of the analyzer is to create a graph of all the classes from the input JAR
+with their dependencies and then only keep the ones we want.
 
-Some classes are basically wrappers over native objects.
-Subclassing doesn't work as most methods are either static or we don't
-control object creation. In this scenario the idea is to be able to
-replace classes in the final jar.
+To do that, the analyzer is created with a list of base classes to keep -- everything
+that derives from these is kept. Currently the one such class is android.view.View:
+since we want to render layouts, anything that is sort of the view needs to be kept.
 
-Example: android.graphics.Paint would get renamed to OriginalPaint
-in the generated jar. Then in the bridge we'll introduce a replacement
-Paint class that derives from OriginalPaint.
+The analyzer is also given a list of class names to keep in the output.
+This is done using shell-like glob patterns that filter on the fully-qualified
+class names, for example "android.*.R**" ("*" does not matches dots whilst "**" does,
+and "." and "$" are interpreted as-is).
+In practice we almost but not quite request the inclusion of full packages.
+
+With this information, the analyzer parses the input zip to find all the classes.
+All classes deriving from the requested bases classes are kept.
+All classes which name matched the glob pattern are kept.
+The analysis then finds all the dependencies of the classes that are to be kept
+using an ASM visitor on the class, the field types, the method types and annotations types.
+Classes that belong to the current JRE are excluded.
+
+The output of the analyzer is a set of ASM ClassReader instances which are then
+fed to the generator.
+
+
+- Generator
+-----------
+
+The generator is constructed from a CreateInfo struct that acts as a config file
+and lists:
+- the classes to inject in the output JAR -- these classes are directly implemented
+  in layoutlib_create and will be used to interface with the renderer in Eclipse.
+- specific methods to override (see method stubs details below).
+- specific methods to remove based on their return type.
+- specific classes to rename.
+
+Each of these are specific strategies we use to be able to modify the Android code
+to fit within the Eclipse renderer. These strategies are explained beow.
+
+The core method of the generator is transform(): it takes an input ASM ClassReader
+and modifies it to produce a byte array suitable for the final JAR file.
+
+The first step of the transformation is changing the name of the class in case
+we requested the class to be renamed. This uses the RenameClassAdapter to also rename
+all inner classes and references in methods and types. Note that other classes are
+not transformed and keep referencing the original name.
+
+The TransformClassAdapter is then used to process the potentially renamed class.
+All protected or private classes are market as public.
+All classes are made non-final.
+Interfaces are left as-is.
+
+If a method has a return type that must be erased, the whole method is skipped.
+Methods are also changed from protected/private to public.
+The code of the methods is then kept as-is, except for native methods which are
+replaced by a stub. Methods that are to be overridden are also replaced by a stub.
+
+Finally fields are also visited and changed from protected/private to public.
+
+
+- Method stubs
+--------------
+
+As indicated above, all native and overridden methods are replaced by a stub.
+We don't have the code to replace with in layoutlib_create.
+Instead the StubMethodAdapter replaces the code of the method by a call to
+OverrideMethod.invokeX(). When using the final JAR, the bridge can register
+listeners from these overridden method calls based on the method signatures.
+
+The listeners are currently pretty basic: we only pass the signature of the
+method being called, its caller object and a flag indicating whether the
+method was native. We do not currently provide the parameters. The listener
+can however specify the return value of the overridden method.
+
+An extension being worked on is to actually replace these listeners by
+direct calls to a delegate class, complete with parameters.
+
+
+- Strategies
+------------
+
+We currently have 4 strategies to deal with overriding the rendering code
+and make it run in Eclipse. Most of these strategies are implemented hand-in-hand
+by the bridge (which runs in Eclipse) and the generator.
+
+
+1- Class Injection
+
+This is the easiest: we currently inject 4 classes, namely:
+- OverrideMethod and its associated MethodListener and MethodAdapter are used
+  to intercept calls to some specific methods that are stubbed out and change
+  their return value.
+- CreateInfo class, which configured the generator. Not used yet, but could
+  in theory help us track what the generator changed.
+
+
+2- Overriding methods
+
+As explained earlier, the creator doesn't have any replacement code for
+methods to override. Instead it removes the original code and replaces it
+by a call to a specific OveriddeMethod.invokeX(). The bridge then registers
+a listener on the method signature and can provide an implementation.
+
+
+3- Renaming classes
+
+This simply changes the name of a class in its definition, as well as all its
+references in internal inner classes and methods.
+Calls from other classes are not modified -- they keep referencing the original
+class name. This allows the bridge to literally replace an implementation.
+
+An example will make this easier: android.graphics.Paint is the main drawing
+class that we need to replace. To do so, the generator renames Paint to _original_Paint.
+Later the bridge provides its own replacement version of Paint which will be used
+by the rest of the Android stack. The replacement version of Paint can still use
+(either by inheritance or delegation) all the original non-native code of _original_Paint
+if it so desires.
+
+Some of the Android classes are basically wrappers over native objects and since
+we don't have the native code in Eclipse, we need to provide a full alternate
+implementation. Sub-classing doesn't work as some native methods are static and
+we don't control object creation.
 
 This won't rename/replace the inner static methods of a given class.
 
 
+4- Method erasure based on return type
 
+This is mostly an implementation detail of the bridge: in the Paint class
+mentioned above, some inner static classes are used to pass around
+attributes (e.g. FontMetrics, or the Style enum) and all the original implementation
+is native.
+
+In this case we have a strategy that tells the generator that anything returning, for
+example, the inner class Paint$Style in the Paint class should be discarded and the
+bridge will provide its own implementation.
+
+
+--
+end
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/Nullable.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/Nullable.java
new file mode 100755
index 0000000..0689c92
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/Nullable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Denotes a parameter or field can be null.
+ * <p/>
+ * When decorating a method call parameter, this denotes the parameter can
+ * legitimately be null and the method will gracefully deal with it. Typically used
+ * on optional parameters.
+ * <p/>
+ * When decorating a method, this denotes the method might legitimately return null.
+ * <p/>
+ * This is a marker annotation and it has no specific attributes.
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface Nullable {
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/VisibleForTesting.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/VisibleForTesting.java
new file mode 100755
index 0000000..e4e016b
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/VisibleForTesting.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Denotes that the class, method or field has its visibility relaxed so
+ * that unit tests can access it.
+ * <p/>
+ * The <code>visibility</code> argument can be used to specific what the original
+ * visibility should have been if it had not been made public or package-private for testing.
+ * The default is to consider the element private.
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface VisibleForTesting {
+    /**
+     * Intended visibility if the element had not been made public or package-private for
+     * testing.
+     */
+    enum Visibility {
+        /** The element should be considered protected. */
+        PROTECTED,
+        /** The element should be considered package-private. */
+        PACKAGE,
+        /** The element should be considered private. */
+        PRIVATE
+    }
+
+    /**
+     * Intended visibility if the element had not been made public or package-private for testing.
+     * If not specified, one should assume the element originally intended to be private.
+     */
+    Visibility visibility() default Visibility.PRIVATE;
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
index 5424efa..722dce2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
@@ -16,6 +16,9 @@
 
 package com.android.tools.layoutlib.create;
 
+import com.android.tools.layoutlib.annotations.VisibleForTesting;
+import com.android.tools.layoutlib.annotations.VisibleForTesting.Visibility;
+
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.Attribute;
 import org.objectweb.asm.ClassVisitor;
@@ -27,13 +30,18 @@
  * Indicates if a class contains any native methods.
  */
 public class ClassHasNativeVisitor implements ClassVisitor {
-    
+
     private boolean mHasNativeMethods = false;
-    
+
     public boolean hasNativeMethods() {
         return mHasNativeMethods;
     }
 
+    @VisibleForTesting(visibility=Visibility.PRIVATE)
+    protected void setHasNativeMethods(boolean hasNativeMethods, String methodName) {
+        mHasNativeMethods = hasNativeMethods;
+    }
+
     public void visit(int version, int access, String name, String signature,
             String superName, String[] interfaces) {
         // pass
@@ -65,7 +73,9 @@
 
     public MethodVisitor visitMethod(int access, String name, String desc,
             String signature, String[] exceptions) {
-        mHasNativeMethods |= ((access & Opcodes.ACC_NATIVE) != 0);
+        if ((access & Opcodes.ACC_NATIVE) != 0) {
+            setHasNativeMethods(true, name);
+        }
         return null;
     }
 
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
new file mode 100644
index 0000000..d6916ae
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+
+/**
+ * Tests {@link ClassHasNativeVisitor}.
+ */
+public class ClassHasNativeVisitorTest {
+
+    @Test
+    public void testHasNative() throws IOException {
+        MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor();
+        ClassReader cr = new ClassReader(
+                "com.android.tools.layoutlib.create.ClassHasNativeVisitorTest$ClassWithNative");
+
+        cr.accept(cv, 0 /* flags */);
+        assertArrayEquals(new String[] { "native_method" }, cv.getMethodsFound());
+        assertTrue(cv.hasNativeMethods());
+    }
+
+    @Test
+    public void testHasNoNative() throws IOException {
+        MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor();
+        ClassReader cr = new ClassReader(
+                "com.android.tools.layoutlib.create.ClassHasNativeVisitorTest$ClassWithoutNative");
+
+        cr.accept(cv, 0 /* flags */);
+        assertArrayEquals(new String[0], cv.getMethodsFound());
+        assertFalse(cv.hasNativeMethods());
+    }
+
+    /**
+     * Overrides {@link ClassHasNativeVisitor} to collec the name of the native methods found.
+     */
+    private static class MockClassHasNativeVisitor extends ClassHasNativeVisitor {
+        private ArrayList<String> mMethodsFound = new ArrayList<String>();
+
+        public String[] getMethodsFound() {
+            return mMethodsFound.toArray(new String[mMethodsFound.size()]);
+        }
+
+        @Override
+        protected void setHasNativeMethods(boolean hasNativeMethods, String methodName) {
+            if (hasNativeMethods) {
+                mMethodsFound.add(methodName);
+            }
+            super.setHasNativeMethods(hasNativeMethods, methodName);
+        }
+    }
+
+    /**
+     * Dummy test class with a native method.
+     */
+    public static class ClassWithNative {
+        public ClassWithNative() {
+        }
+
+        public void callTheNativeMethod() {
+            native_method();
+        }
+
+        private native void native_method();
+    }
+
+    /**
+     * Dummy test class with no native method.
+     */
+    public static class ClassWithoutNative {
+        public ClassWithoutNative() {
+        }
+
+        public void someMethod() {
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 8028fe7..bcbd07c 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -322,6 +322,7 @@
     private static String LS = System.getProperty("line.separator");
 
     private static String[] sDnsPropNames;
+    private Runnable mReleaseWakeLockCallback;
 
     /**
      * Keep track of whether we last told the battery stats we had started.
@@ -1475,7 +1476,7 @@
         int netId = -1;
         String[] lines = reply.split("\n");
         for (String line : lines) {
-            String[] prop = line.split(" *= *");
+            String[] prop = line.split(" *= *", 2);
             if (prop.length < 2)
                 continue;
             String name = prop[0];
@@ -2446,11 +2447,11 @@
                         setBluetoothCoexistenceMode(
                                 WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
                     }
-
+                    
                     powerMode = getPowerMode();
                     if (powerMode < 0) {
-                        // Handle the case where supplicant driver does not support
-                        // getPowerModeCommand.
+                      // Handle the case where supplicant driver does not support
+                      // getPowerModeCommand.
                         powerMode = DRIVER_POWER_MODE_AUTO;
                     }
                     if (powerMode != DRIVER_POWER_MODE_ACTIVE) {