Merge "Return count of rows in a resultset only once (when startPos = 0)"
diff --git a/Android.mk b/Android.mk
index b4090a7..63505ac 100644
--- a/Android.mk
+++ b/Android.mk
@@ -366,6 +366,7 @@
     -since ./frameworks/base/api/8.xml 8 \
     -since ./frameworks/base/api/current.xml HC \
 		-error 101 -error 102 -warning 103 -error 104 -error 106 -error 108 -warning 113 \
+		-error 114 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
 framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework)
diff --git a/api/current.xml b/api/current.xml
index 589ec10..819c730 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2088,6 +2088,28 @@
  visibility="public"
 >
 </field>
+<field name="actionBarSize"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843563"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="actionBarStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843535"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="actionBarTabBarStyle"
  type="int"
  transient="false"
@@ -3078,6 +3100,17 @@
  visibility="public"
 >
 </field>
+<field name="closeButtonStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="codes"
  type="int"
  transient="false"
@@ -5388,6 +5421,17 @@
  visibility="public"
 >
 </field>
+<field name="itemPadding"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843575"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="itemTextAppearance"
  type="int"
  transient="false"
@@ -9260,6 +9304,17 @@
  visibility="public"
 >
 </field>
+<field name="subtitleTextStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843578"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="suggestActionMsg"
  type="int"
  transient="false"
@@ -10096,6 +10151,17 @@
  visibility="public"
 >
 </field>
+<field name="titleTextStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843577"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="to"
  type="int"
  transient="false"
@@ -10723,28 +10789,6 @@
  visibility="public"
 >
 </field>
-<field name="windowActionBarSize"
- type="int"
- transient="false"
- volatile="false"
- value="16843563"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="windowActionBarStyle"
- type="int"
- transient="false"
- volatile="false"
- value="16843535"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="windowActionModeOverlay"
  type="int"
  transient="false"
@@ -67258,6 +67302,1615 @@
 </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="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>
+</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_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_NOT_SUPPORTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_NO_INTERNET_CONNECTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_OUT_OF_MEMORY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ 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_RIGHTS_NOT_INSTALLED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_RENEWAL_NOT_ALLOWED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_WAIT_FOR_RIGHTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ 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="android.drm.DrmInfo"
+ 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="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="path" type="java.lang.String">
+</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="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="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="loadPlugIns"
+ return="void"
+ 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="android.drm.DrmInfoStatus"
+ 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="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeRights"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="saveRights"
+ return="void"
+ 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="setOnInfoListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="infoListener" type="android.drm.DrmManagerClient.OnInfoListener">
+</parameter>
+</method>
+<method name="unloadPlugIns"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<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"
@@ -104218,7 +105871,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;id&quot;"
+ value="&quot;_id&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 01cddc6..a57a72f 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_RADIO, "radio.phone" },
     { AID_RADIO, "radio.sms" },
     { AID_RADIO, "radio.phonesubinfo" },
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9f7bef4..da000e5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -111,9 +111,8 @@
     /**
      * An intent to launch instead of posting the notification to the status bar.
      * Only for use with extremely high-priority notifications demanding the user's
-     * <strong>immediate</strong>attention, such as an incoming phone call or
+     * <strong>immediate</strong> attention, such as an incoming phone call or
      * alarm clock that the user has explicitly set to a particular time.
-     * call (handled in the core Android Phone app with a full-screen Activity).
      * If this facility is used for something else, please give the user an option
      * to turn it off and use a normal notification, as this can be extremely
      * disruptive.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 05ebd07..61fc9e6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -105,6 +105,14 @@
      * it with {@link android.content.Intent#getStringExtra(String)}.
      */
     public static final String EXTRA_EXTRA_INFO = "extraInfo";
+    /**
+     * The lookup key for an int that provides information about
+     * our connection to the internet at large.  0 indicates no connection,
+     * 100 indicates a great connection.  Retrieve it with
+     * {@link android.content.Intent@getIntExtra(String)}.
+     * {@hide}
+     */
+    public static final String EXTRA_INET_CONDITION = "inetCondition";
 
     /**
      * Broadcast Action: The setting for background data usage has changed
@@ -575,4 +583,16 @@
             return false;
         }
     }
+
+    /**
+     * @param networkType The type of network you want to report on
+     * @param percentage The quality of the connection 0 is bad, 100 is good
+     * {@hide}
+     */
+    public void reportInetCondition(int networkType, int percentage) {
+        try {
+            mService.reportInetCondition(networkType, percentage);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
index cafe0f9..e04367a 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/net/DownloadManager.java
@@ -21,6 +21,7 @@
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.os.ParcelFileDescriptor;
+import android.provider.BaseColumns;
 import android.provider.Downloads;
 
 import java.io.File;
@@ -48,7 +49,7 @@
      * An identifier for a particular download, unique across the system.  Clients use this ID to
      * make subsequent calls related to the download.
      */
-    public final static String COLUMN_ID = "id";
+    public final static String COLUMN_ID = BaseColumns._ID;
 
     /**
      * The client-supplied title for this download.  This will be displayed in system notifications.
@@ -441,8 +442,22 @@
      * This class may be used to filter download manager queries.
      */
     public static class Query {
-        private Long mId;
+        /**
+         * Constant for use with {@link #orderBy}
+         * @hide
+         */
+        public static final int ORDER_ASCENDING = 1;
+
+        /**
+         * Constant for use with {@link #orderBy}
+         * @hide
+         */
+        public static final int ORDER_DESCENDING = 2;
+
+        private Long mId = null;
         private Integer mStatusFlags = null;
+        private String mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
+        private int mOrderDirection = ORDER_DESCENDING;
 
         /**
          * Include only the download with the given ID.
@@ -464,6 +479,32 @@
         }
 
         /**
+         * Change the sort order of the returned Cursor.
+         *
+         * @param column one of the COLUMN_* constants; currently, only
+         *         {@link #COLUMN_LAST_MODIFIED_TIMESTAMP} and {@link #COLUMN_TOTAL_SIZE_BYTES} are
+         *         supported.
+         * @param direction either {@link #ORDER_ASCENDING} or {@link #ORDER_DESCENDING}
+         * @return this object
+         * @hide
+         */
+        public Query orderBy(String column, int direction) {
+            if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
+                throw new IllegalArgumentException("Invalid direction: " + direction);
+            }
+
+            if (column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP)) {
+                mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
+            } else if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
+                mOrderByColumn = Downloads.COLUMN_TOTAL_BYTES;
+            } else {
+                throw new IllegalArgumentException("Cannot order by " + column);
+            }
+            mOrderDirection = direction;
+            return this;
+        }
+
+        /**
          * Run this query using the given ContentResolver.
          * @param projection the projection to pass to ContentResolver.query()
          * @return the Cursor returned by ContentResolver.query()
@@ -497,7 +538,10 @@
                 }
                 selection = joinStrings(" OR ", parts);
             }
-            String orderBy = Downloads.COLUMN_LAST_MODIFICATION + " DESC";
+
+            String orderDirection = (mOrderDirection == ORDER_ASCENDING ? "ASC" : "DESC");
+            String orderBy = mOrderByColumn + " " + orderDirection;
+
             return resolver.query(uri, projection, selection, null, orderBy);
         }
 
@@ -567,6 +611,9 @@
      */
     public Cursor query(Query query) {
         Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS);
+        if (underlyingCursor == null) {
+            return null;
+        }
         return new CursorTranslator(underlyingCursor);
     }
 
@@ -608,7 +655,7 @@
         public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
             int index = getColumnIndex(columnName);
             if (index == -1) {
-                throw new IllegalArgumentException();
+                throw new IllegalArgumentException("No such column: " + columnName);
             }
             return index;
         }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index f31fb75..9f2fc17 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -78,4 +78,6 @@
     String[] getTetherableBluetoothRegexs();
 
     void requestNetworkTransitionWakelock(in String forWhom);
+
+    void reportInetCondition(int networkType, int percentage);
 }
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 420992b..5420d8f 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -71,6 +71,18 @@
     public static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 7;
 
     /**
+     * msg.arg1 = network type
+     * msg.arg2 = condition (0 bad, 100 good)
+     */
+    public static final int EVENT_INET_CONDITION_CHANGE = 8;
+
+    /**
+     * msg.arg1 = network type
+     * msg.arg2 = default connection sequence number
+     */
+    public static final int EVENT_INET_CONDITION_HOLD_END = 9;
+
+    /**
      * -------------------------------------------------------------
      * Control Interface
      * -------------------------------------------------------------
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 32fb108..f5b1e57 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1585,10 +1585,10 @@
                                 sb.append(ent.getKey()); sb.append(":\n");
                         sb.append(prefix); sb.append("      CPU: ");
                                 formatTime(sb, userTime); sb.append("usr + ");
-                                formatTime(sb, systemTime); sb.append("krn\n");
+                                formatTime(sb, systemTime); sb.append("krn");
                         if (starts != 0) {
-                            sb.append(prefix); sb.append("      "); sb.append(starts);
-                                    sb.append(" proc starts");
+                            sb.append("\n"); sb.append(prefix); sb.append("      ");
+                                    sb.append(starts); sb.append(" proc starts");
                         }
                         pw.println(sb.toString());
                         for (int e=0; e<numExcessive; e++) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 2b8a8e6..d3718f8 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -273,7 +273,9 @@
      }
 
     /**
-     * Media provider interface used by MTP implementation.
+     * Media provider table containing an index of all files in the storage.
+     * This can be used by applications to find all documents of a particular type
+     * and is also used internally by the device side MTP implementation.
      * @hide
      */
     public static final class Files {
@@ -289,11 +291,22 @@
                     + "/file/" + fileId);
         }
 
-        // used for MTP GetObjectReferences and SetObjectReferences
-        public static final Uri getReferencesUri(String volumeName,
+        public static Uri getMtpObjectsUri(String volumeName) {
+            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
+                    "/object");
+        }
+
+        public static final Uri getMtpObjectsUri(String volumeName,
                 long fileId) {
             return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
-                    + "/file/" + fileId + "/references");
+                    + "/object/" + fileId);
+        }
+
+        // Used to implement the MTP GetObjectReferences and SetObjectReferences commands.
+        public static final Uri getMtpReferencesUri(String volumeName,
+                long fileId) {
+            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
+                    + "/object/" + fileId + "/references");
         }
 
         /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 567ee93..6af6a81 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3471,6 +3471,21 @@
         public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
                 "download_manager_max_bytes_over_mobile";
 
+        /**
+         * ms during which to consume extra events related to Inet connection condition
+         * after a transtion to fully-connected
+         * @hide
+         */
+        public static final String INET_CONDITION_DEBOUNCE_UP_DELAY =
+                "inet_condition_debounce_up_delay";
+
+        /**
+         * ms during which to consume extra events related to Inet connection condtion
+         * after a transtion to partly-connected
+         * @hide
+         */
+        public static final String INET_CONDITION_DEBOUNCE_DOWN_DELAY =
+                "inet_condition_debounce_down_delay";
 
         /**
          * @hide
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 48a2b72..fde3769 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -417,7 +417,13 @@
             mBluetoothService.sendUuidIntent(address);
         } else if (name.equals("Paired")) {
             if (propValues[1].equals("true")) {
-                mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
+                // If locally initiated pairing, we will
+                // not go to BOND_BONDED state until we have received a
+                // successful return value in onCreatePairedDeviceResult
+                if (null == mBluetoothService.getBondState().getPendingOutgoingBonding()) {
+                    mBluetoothService.getBondState().setBondState(address,
+                            BluetoothDevice.BOND_BONDED);
+                }
             } else {
                 mBluetoothService.getBondState().setBondState(address,
                         BluetoothDevice.BOND_NONE);
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index fb88c71..b1fdec8 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -41,6 +41,7 @@
     private static final int MAX_AGE_MILLISECONDS = 200;
     
     private static final int POINTER_POOL_CAPACITY = 20;
+    private static final int INVALID_POINTER = -1;
 
     private static final Pool<VelocityTracker> sPool = Pools.synchronizedPool(
             Pools.finitePool(new PoolableManager<VelocityTracker>() {
@@ -76,6 +77,7 @@
     private Pointer mPointerListHead; // sorted by id in increasing order
     private int mLastTouchIndex;
     private int mGeneration;
+    private int mActivePointerId;
 
     private VelocityTracker mNext;
 
@@ -125,6 +127,7 @@
         
         mPointerListHead = null;
         mLastTouchIndex = 0;
+        mActivePointerId = INVALID_POINTER;
     }
     
     /**
@@ -180,6 +183,10 @@
                 // Pointer went down.  Add it to the list.
                 // Write a sentinel at the end of the pastTime trace so we will be able to
                 // tell when the trace started.
+                if (mActivePointerId == INVALID_POINTER) {
+                    // Congratulations! You're the new active pointer!
+                    mActivePointerId = pointerId;
+                }
                 pointer = obtainPointer();
                 pointer.id = pointerId;
                 pointer.pastTime[lastTouchIndex] = Long.MIN_VALUE;
@@ -214,6 +221,7 @@
         previousPointer = null;
         for (Pointer pointer = mPointerListHead; pointer != null; ) {
             final Pointer nextPointer = pointer.next;
+            final int pointerId = pointer.id;
             if (pointer.generation != generation) {
                 // Pointer went up.  Remove it from the list.
                 if (previousPointer == null) {
@@ -222,6 +230,12 @@
                     previousPointer.next = nextPointer;
                 }
                 releasePointer(pointer);
+
+                if (pointerId == mActivePointerId) {
+                    // Pick a new active pointer. How is arbitrary.
+                    mActivePointerId = mPointerListHead != null ?
+                            mPointerListHead.id : INVALID_POINTER;
+                }
             } else {
                 previousPointer = pointer;
             }
@@ -334,7 +348,7 @@
      * @return The previously computed X velocity.
      */
     public float getXVelocity() {
-        Pointer pointer = getPointer(0);
+        Pointer pointer = getPointer(mActivePointerId);
         return pointer != null ? pointer.xVelocity : 0;
     }
     
@@ -345,7 +359,7 @@
      * @return The previously computed Y velocity.
      */
     public float getYVelocity() {
-        Pointer pointer = getPointer(0);
+        Pointer pointer = getPointer(mActivePointerId);
         return pointer != null ? pointer.yVelocity : 0;
     }
     
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5d258967..833fa70 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5094,20 +5094,23 @@
                 }
             }
             mMatrix.reset();
-            mMatrix.setTranslate(mTranslationX, mTranslationY);
-            mMatrix.preRotate(mRotation, mPivotX, mPivotY);
-            mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
-            if (nonzero(mRotationX) || nonzero(mRotationY)) {
+            if (!nonzero(mRotationX) && !nonzero(mRotationY)) {
+                mMatrix.setTranslate(mTranslationX, mTranslationY);
+                mMatrix.preRotate(mRotation, mPivotX, mPivotY);
+                mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+            } else {
                 if (mCamera == null) {
                     mCamera = new Camera();
                     matrix3D = new Matrix();
                 }
                 mCamera.save();
+                mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
                 mCamera.rotateX(mRotationX);
                 mCamera.rotateY(mRotationY);
+                mCamera.rotateZ(-mRotation);
                 mCamera.getMatrix(matrix3D);
                 matrix3D.preTranslate(-mPivotX, -mPivotY);
-                matrix3D.postTranslate(mPivotX, mPivotY);
+                matrix3D.postTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY);
                 mMatrix.postConcat(matrix3D);
                 mCamera.restore();
             }
@@ -5148,7 +5151,8 @@
     }
 
     /**
-     * Sets the degrees that the view is rotated around the pivot point.
+     * Sets the degrees that the view is rotated around the pivot point. Increasing values
+     * result in clockwise rotation.
      *
      * @param rotation The degrees of rotation.
      * @see #getPivotX()
@@ -5177,7 +5181,9 @@
     }
 
     /**
-     * Sets the degrees that the view is rotated around the vertical axis through pivot point.
+     * Sets the degrees that the view is rotated around the vertical axis through the pivot point.
+     * Increasing values result in counter-clockwise rotation from the viewpoint of looking
+     * down the y axis.
      *
      * @param rotationY The degrees of Y rotation.
      * @see #getPivotX()
@@ -5206,7 +5212,9 @@
     }
 
     /**
-     * Sets the degrees that the view is rotated around the horizontal axis through pivot point.
+     * Sets the degrees that the view is rotated around the horizontal axis through the pivot point.
+     * Increasing values result in clockwise rotation from the viewpoint of looking down the
+     * x axis.
      *
      * @param rotationX The degrees of X rotation.
      * @see #getPivotX()
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 52a117d..d171990 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -284,7 +284,7 @@
     // only called from WebCore Thread
     // make sure to call startCacheTransaction/endCacheTransaction in pair
     /**
-     * @deprecated Not used
+     * @deprecated Always returns false.
      */
     @Deprecated
     public static boolean startCacheTransaction() {
@@ -294,7 +294,7 @@
     // only called from WebCore Thread
     // make sure to call startCacheTransaction/endCacheTransaction in pair
     /**
-     * @deprecated Not used
+     * @deprecated Always returns false.
      */
     @Deprecated
     public static boolean endCacheTransaction() {
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 6c11a7f..fca5ee1 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -635,10 +635,23 @@
         mWebView.requestFocus();
     }
 
+    /**
+     * Move the caret/selection into view.
+     */
     /* package */ void bringIntoView() {
-        if (getLayout() != null) {
-            bringPointIntoView(Selection.getSelectionEnd(getText()));
+        bringPointIntoView(Selection.getSelectionEnd(getText()));
+    }
+
+    @Override
+    public boolean bringPointIntoView(int offset) {
+        if (mWebView == null) return false;
+        if (mWebView.nativeFocusCandidateIsPassword()) {
+            return getLayout() != null && super.bringPointIntoView(offset);
         }
+        // For non password text input, tell webkit to move the caret/selection
+        // on screen, since webkit draws them.
+        mWebView.revealSelection();
+        return true;
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b83edc7..bc85444 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3674,10 +3674,10 @@
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
 
         // bring it back to the reading level scale so that user can enter text
-        boolean zoom = mZoomManager.getScale() < mZoomManager.getReadingLevelScale();
+        boolean zoom = mZoomManager.getScale() < mZoomManager.getDefaultScale();
         if (zoom) {
             mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
-            mZoomManager.setZoomScale(mZoomManager.getReadingLevelScale(), false);
+            mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false);
         }
         if (isTextView) {
             rebuildWebTextView();
@@ -3689,7 +3689,7 @@
                 return;
             }
         }
-        // Used by plugins.
+        // Used by plugins and contentEditable.
         // Also used if the navigation cache is out of date, and
         // does not recognize that a textfield is in focus.  In that
         // case, use WebView as the targeted view.
@@ -3782,6 +3782,15 @@
     }
 
     /**
+     * Tell webkit to put the cursor on screen.
+     */
+    /* package */ void revealSelection() {
+        if (mWebViewCore != null) {
+            mWebViewCore.sendMessage(EventHub.REVEAL_SELECTION);
+        }
+    }
+
+    /**
      * Called by WebTextView to find saved form data associated with the
      * textfield
      * @param name Name of the textfield.
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index fad4323..60ddf08 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -731,6 +731,7 @@
     }
 
         static final String[] HandlerDebugString = {
+            "REVEAL_SELECTION", // 96
             "REQUEST_LABEL", // 97
             "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
             "SCROLL_TEXT_INPUT", // = 99
@@ -786,6 +787,7 @@
 
     class EventHub {
         // Message Ids
+        static final int REVEAL_SELECTION = 96;
         static final int REQUEST_LABEL = 97;
         static final int UPDATE_FRAME_CACHE_IF_LOADING = 98;
         static final int SCROLL_TEXT_INPUT = 99;
@@ -907,6 +909,9 @@
          */
         private EventHub() {}
 
+        private static final int FIRST_PACKAGE_MSG_ID = REVEAL_SELECTION;
+        private static final int LAST_PACKAGE_MSG_ID = VALID_NODE_BOUNDS;
+
         /**
          * Transfer all messages to the newly created webcore thread handler.
          */
@@ -918,11 +923,11 @@
                 @Override
                 public void handleMessage(Message msg) {
                     if (DebugFlags.WEB_VIEW_CORE) {
-                        Log.v(LOGTAG, (msg.what < REQUEST_LABEL
-                                || msg.what
-                                > VALID_NODE_BOUNDS ? Integer.toString(msg.what)
+                        Log.v(LOGTAG, (msg.what < FIRST_PACKAGE_MSG_ID
+                                || msg.what > LAST_PACKAGE_MSG_ID
+                                ? Integer.toString(msg.what)
                                 : HandlerDebugString[msg.what
-                                        - REQUEST_LABEL])
+                                        - FIRST_PACKAGE_MSG_ID])
                                 + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
                                 + " obj=" + msg.obj);
                     }
@@ -943,6 +948,10 @@
                             }
                             break;
 
+                        case REVEAL_SELECTION:
+                            nativeRevealSelection();
+                            break;
+
                         case REQUEST_LABEL:
                             if (mWebView != null) {
                                 int nodePointer = msg.arg2;
@@ -2306,6 +2315,7 @@
     }
 
     private native void nativeUpdateFrameCacheIfLoading();
+    private native void nativeRevealSelection();
     private native String nativeRequestLabel(int framePtr, int nodePtr);
     /**
      * Scroll the focused textfield to (xPercent, y) in document space
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index cd1e422..70b9d59 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -29,7 +29,7 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.RemoteException;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -43,8 +43,7 @@
  */
 /** @hide */
 public class RemoteViewsAdapter extends BaseAdapter {
-
-    private static final String LOG_TAG = "RemoteViewsAdapter";
+    private static final String TAG = "RemoteViewsAdapter";
 
     private Context mContext;
     private Intent mIntent;
@@ -140,6 +139,8 @@
      * An internal cache of remote views.
      */
     private class RemoteViewsCache {
+        private static final String TAG = "RemoteViewsCache";
+
         private RemoteViewsInfo mViewCacheInfo;
         private RemoteViewsIndexInfo[] mViewCache;
         private int[] mTmpViewCacheLoadIndices;
@@ -249,7 +250,8 @@
 
         private final int getCacheIndex(int position) {
             // take the modulo of the position
-            return (mViewCache.length + (position % mViewCache.length)) % mViewCache.length;
+            final int cacheSize = mViewCache.length;
+            return (cacheSize + (position % cacheSize)) % cacheSize;
         }
 
         public void requestMetaData() {
@@ -278,8 +280,20 @@
                             mFirstViewHeight = -1;
                         }
                     }
-                } catch (RemoteException e) {
-                    e.printStackTrace();
+                } catch (Exception e) {
+                    // print the error
+                    Log.e(TAG, "Error in requestMetaData(): " + e.getMessage());
+
+                    // reset any members after the failed call
+                    synchronized (mViewCacheInfo) {
+                        RemoteViewsInfo info = mViewCacheInfo;
+                        info.hasStableIds = false;
+                        info.viewTypeCount = 1;
+                        info.count = 0;
+                        mUserLoadingView = null;
+                        mFirstView = null;
+                        mFirstViewHeight = -1;
+                    }
                 }
             }
         }
@@ -297,11 +311,15 @@
             if (mServiceConnection.isConnected()) {
                 IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
                 try {
+                    // call back to the factory
                     factory.onDataSetChanged();
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                }
+                } catch (Exception e) {
+                    // print the error
+                    Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
 
+                    // return early to prevent container from being notified (nothing has changed)
+                    return;
+                }
             }
 
             // re-request the new metadata (only after the notification to the factory)
@@ -327,8 +345,15 @@
                 try {
                     remoteView = factory.getViewAt(position);
                     itemId = factory.getItemId(position);
-                } catch (RemoteException e) {
+                } catch (Exception e) {
+                    // print the error
+                    Log.e(TAG, "Error in updateRemoteViewsInfo(" + position + "): " +
+                            e.getMessage());
                     e.printStackTrace();
+
+                    // return early to prevent additional work in re-centering the view cache, and
+                    // swapping from the loading view
+                    return;
                 }
 
                 synchronized (mViewCache) {
@@ -560,13 +585,6 @@
                         } else {
                             // otherwise, try and load the item
                             updateRemoteViewsInfo(index);
-
-                            // sleep for a bit to allow things to catch up after the load
-                            try {
-                                Thread.sleep(50);
-                            } catch (InterruptedException e) {
-                                e.printStackTrace();
-                            }
                         }
                     }
                 }
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 0a97904..2aa0bc6 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -215,27 +215,39 @@
 
         // Implement the faked perspective
         if (toIndex != -1) {
-            float maxPerpectiveShift = mViewHeight * PERSPECTIVE_SHIFT_FACTOR;
-            int index = toIndex;
+            transformViewAtIndex(toIndex, view);
+        }
+    }
 
-            if (toIndex == mNumActiveViews -1) index--;
+    private void transformViewAtIndex(int index, View view) {
+        float maxPerpectiveShift = mViewHeight * PERSPECTIVE_SHIFT_FACTOR;
 
-            float r = (index * 1.0f) / (mNumActiveViews - 2);
+        if (index == mNumActiveViews -1) index--;
 
-            float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
-            PropertyValuesHolder<Float> scaleX = new PropertyValuesHolder<Float>("scaleX", scale);
-            PropertyValuesHolder<Float> scaleY = new PropertyValuesHolder<Float>("scaleY", scale);
+        float r = (index * 1.0f) / (mNumActiveViews - 2);
 
-            r = (float) Math.pow(r, 2);
+        float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
+        PropertyValuesHolder<Float> scaleX = new PropertyValuesHolder<Float>("scaleX", scale);
+        PropertyValuesHolder<Float> scaleY = new PropertyValuesHolder<Float>("scaleY", scale);
 
-            int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
-            float transY = -stackDirection * r * maxPerpectiveShift +
-                    stackDirection * (1 - scale) * (mViewHeight / 2.0f);
+        r = (float) Math.pow(r, 2);
 
-            PropertyValuesHolder<Float> translationY =
-                    new PropertyValuesHolder<Float>("translationY", transY);
-            ObjectAnimator pa = new ObjectAnimator(100, view, scaleX, scaleY, translationY);
-            pa.start();
+        int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+        float transY = -stackDirection * r * maxPerpectiveShift +
+                stackDirection * (1 - scale) * (mViewHeight / 2.0f);
+
+        PropertyValuesHolder<Float> translationY =
+                new PropertyValuesHolder<Float>("translationY", transY);
+        ObjectAnimator pa = new ObjectAnimator(100, view, scaleX, scaleY, translationY);
+        pa.start();
+    }
+
+    private void updateChildTransforms() {
+        for (int i = 0; i < mNumActiveViews - 1; i++) {
+            View v = getViewAtRelativeIndex(i);
+            if (v != null) {
+                transformViewAtIndex(i, v);
+            }
         }
     }
 
@@ -271,6 +283,7 @@
     private void onLayout() {
         if (!mFirstLayoutHappened) {
             mViewHeight = Math.round(SLIDE_UP_RATIO * getMeasuredHeight());
+            updateChildTransforms();
             mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO * mViewHeight);
             mFirstLayoutHappened = true;
         }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c87264a..b8c9e72 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5819,18 +5819,25 @@
     }
 
     private void convertFromViewportToContentCoordinates(Rect r) {
-        int paddingTop = getExtendedPaddingTop();
+        final int horizontalOffset = viewportToContentHorizontalOffset();
+        r.left += horizontalOffset;
+        r.right += horizontalOffset;
+
+        final int verticalOffset = viewportToContentVerticalOffset();
+        r.top += verticalOffset;
+        r.bottom += verticalOffset;
+    }
+
+    private int viewportToContentHorizontalOffset() {
+        return getCompoundPaddingLeft() - mScrollX;
+    }
+
+    private int viewportToContentVerticalOffset() {
+        int offset = getExtendedPaddingTop() - mScrollY;
         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
-            paddingTop += getVerticalOffset(false);
+            offset += getVerticalOffset(false);
         }
-        r.top += paddingTop;
-        r.bottom += paddingTop;
-
-        int paddingLeft = getCompoundPaddingLeft();
-        r.left += paddingLeft;
-        r.right += paddingLeft;
-
-        r.offset(-mScrollX, -mScrollY);
+        return offset;
     }
 
     @Override
@@ -6550,6 +6557,8 @@
             if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
                 // Has to be done before onTakeFocus, which can be overloaded.
                 if (mLastTouchOffset >= 0) {
+                    // Can happen when a TextView is displayed after its content has been deleted.
+                    mLastTouchOffset = Math.min(mLastTouchOffset, mText.length());
                     Selection.setSelection((Spannable) mText, mLastTouchOffset);
                 }
 
@@ -6566,7 +6575,8 @@
                 // ExtractEditText clears focus, which gives focus to the ExtractEditText.
                 // This special case ensure that we keep current selection in that case.
                 // It would be better to know why the DecorView does not have focus at that time.
-                if (((this instanceof ExtractEditText) || mSelectionMoved) && selStart >= 0 && selEnd >= 0) {
+                if (((this instanceof ExtractEditText) || mSelectionMoved) &&
+                        selStart >= 0 && selEnd >= 0) {
                     /*
                      * Someone intentionally set the selection, so let them
                      * do whatever it is that they wanted to do instead of
@@ -6682,6 +6692,8 @@
 
         if (start == end) {
             if (start >= prevStart && start < prevEnd) {
+                // Restore previous selection
+                Selection.setSelection((Spannable)mText, prevStart, prevEnd);
                 // Tapping inside the selection displays the cut/copy/paste context menu.
                 showContextMenu();
                 return;
@@ -7736,9 +7748,7 @@
             bounds.right = bounds.left + drawableWidth;
             bounds.bottom = bounds.top + drawableHeight;
 
-            int boundTopBefore = bounds.top;
             convertFromViewportToContentCoordinates(bounds);
-            mHotSpotVerticalPosition += bounds.top - boundTopBefore;
             mDrawable.setBounds(bounds);
             postInvalidate();
         }
@@ -7882,6 +7892,9 @@
                             mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
                             mOffsetY = mHandle.mHotSpotVerticalPosition - y;
 
+                            mOffsetX += viewportToContentHorizontalOffset();
+                            mOffsetY += viewportToContentVerticalOffset();
+
                             mOnDownTimerStart = event.getEventTime();
                         }
                         break;
@@ -8069,6 +8082,9 @@
                                     mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
                                     mOffsetY = draggedHandle.mHotSpotVerticalPosition - y;
 
+                                    mOffsetX += viewportToContentHorizontalOffset();
+                                    mOffsetY += viewportToContentVerticalOffset();
+
                                     ((ArrowKeyMovementMethod)mMovement).setCursorController(this);
                                 }
                             }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9ed3658..b9f0c61 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1378,13 +1378,13 @@
                 for (int i=0; i<N; i++) {
                     StopwatchTimer st = mPartialTimers.get(i);
                     if (st.mInList) {
-                        int myUTime = utime/num;
-                        int mySTime = stime/num;
-                        utime -= myUTime;
-                        stime -= mySTime;
-                        num--;
                         Uid uid = st.mUid;
                         if (uid != null && uid.mUid != Process.SYSTEM_UID) {
+                            int myUTime = utime/num;
+                            int mySTime = stime/num;
+                            utime -= myUTime;
+                            stime -= mySTime;
+                            num--;
                             Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
                             proc.addCpuTimeLocked(myUTime, mySTime);
                             proc.addSpeedStepTimes(cpuSpeedTimes);
@@ -3633,7 +3633,9 @@
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = getPidStatsLocked(pid);
-                p.mWakeStart = SystemClock.elapsedRealtime();
+                if (p.mWakeStart == 0) {
+                    p.mWakeStart = SystemClock.elapsedRealtime();
+                }
             }
         }
 
@@ -3644,7 +3646,7 @@
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = mPids.get(pid);
-                if (p != null) {
+                if (p != null && p.mWakeStart != 0) {
                     p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
                     p.mWakeStart = 0;
                 }
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index acf75e3..6b7b946 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -37,7 +37,6 @@
  */
 public class ActionBarContextView extends ViewGroup {
     private int mItemPadding;
-    private int mItemMargin;
     private int mActionSpacing;
     private int mContentHeight;
     
@@ -49,32 +48,36 @@
     private LinearLayout mTitleLayout;
     private TextView mTitleView;
     private TextView mSubtitleView;
-    private Drawable mCloseDrawable;
+    private int mCloseButtonStyle;
+    private int mTitleStyleRes;
+    private int mSubtitleStyleRes;
     private ActionMenuView mMenuView;
     
     public ActionBarContextView(Context context) {
-        this(context, null, 0);
+        this(context, null);
     }
     
     public ActionBarContextView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, com.android.internal.R.attr.actionModeStyle);
     }
     
     public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                com.android.internal.R.styleable.Theme);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionMode, defStyle, 0);
         mItemPadding = a.getDimensionPixelOffset(
-                com.android.internal.R.styleable.Theme_actionButtonPadding, 0);
+                com.android.internal.R.styleable.ActionMode_itemPadding, 0);
         setBackgroundDrawable(a.getDrawable(
-                com.android.internal.R.styleable.Theme_actionModeBackground));
-        mCloseDrawable = a.getDrawable(
-                com.android.internal.R.styleable.Theme_actionModeCloseDrawable);
-        mItemMargin = mItemPadding / 2;
+                com.android.internal.R.styleable.ActionMode_background));
+        mCloseButtonStyle = a.getResourceId(
+                com.android.internal.R.styleable.ActionMode_closeButtonStyle, 0);
+        mTitleStyleRes = a.getResourceId(
+                com.android.internal.R.styleable.ActionMode_titleTextStyle, 0);
+        mSubtitleStyleRes = a.getResourceId(
+                com.android.internal.R.styleable.ActionMode_subtitleTextStyle, 0);
 
         mContentHeight = a.getLayoutDimension(
-                com.android.internal.R.styleable.Theme_windowActionBarSize, 0);
+                com.android.internal.R.styleable.ActionMode_height, 0);
         a.recycle();
     }
     
@@ -129,9 +132,15 @@
             mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
             if (mTitle != null) {
                 mTitleView.setText(mTitle);
+                if (mTitleStyleRes != 0) {
+                    mTitleView.setTextAppearance(mContext, mTitleStyleRes);
+                }
             }
             if (mSubtitle != null) {
                 mSubtitleView.setText(mSubtitle);
+                if (mSubtitleStyleRes != 0) {
+                    mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
+                }
                 mSubtitleView.setVisibility(VISIBLE);
             }
             addView(mTitleLayout);
@@ -147,9 +156,7 @@
 
     public void initForMode(final ActionMode mode) {
         if (mCloseButton == null) {
-            mCloseButton = new ImageButton(getContext());
-            mCloseButton.setImageDrawable(mCloseDrawable);
-            mCloseButton.setBackgroundDrawable(null);
+            mCloseButton = new ImageButton(getContext(), null, mCloseButtonStyle);
         }
         mCloseButton.setOnClickListener(new OnClickListener() {
             public void onClick(View v) {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 254d9a4..6745b24 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -16,6 +16,7 @@
 #include <utils/ResourceTypes.h>
 #include <netinet/in.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 
 jclass gOptions_class;
 jfieldID gOptions_justBoundsFieldID;
@@ -559,7 +560,27 @@
     }
 }
 
-static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream, bool isShareable) {
+static SkMemoryStream* buildSkMemoryStream(SkStream *stream) {
+    size_t bufferSize = 4096;
+    size_t streamLen = 0;
+    size_t len;
+    char* data = (char*)sk_malloc_throw(bufferSize);
+
+    while ((len = stream->read(data + streamLen,
+                    bufferSize - streamLen)) != 0) {
+        streamLen += len;
+        if (streamLen == bufferSize) {
+            bufferSize *= 2;
+            data = (char*)sk_realloc_throw(data, bufferSize);
+        }
+    }
+    data = (char*)sk_realloc_throw(data, streamLen);
+    SkMemoryStream* streamMem = new SkMemoryStream();
+    streamMem->setMemoryOwned(data, streamLen);
+    return streamMem;
+}
+
+static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
     int width, height;
     if (NULL == decoder) {
@@ -574,9 +595,10 @@
     javaAllocator->unref();
     javaMemoryReporter->unref();
 
-    if (!decoder->buildTileIndex(stream, &width, &height, isShareable)) {
-        char msg[1024];
-        snprintf(msg, 1023, "Image failed to decode using %s decoder", decoder->getFormatName());
+    if (!decoder->buildTileIndex(stream, &width, &height)) {
+        char msg[100];
+        snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
+                decoder->getFormatName());
         doThrowIOE(env, msg);
         return nullObjectReturn("decoder->buildTileIndex returned false");
     }
@@ -588,13 +610,13 @@
 
 static jobject nativeCreateLargeBitmapFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
                                      int offset, int length, jboolean isShareable) {
+    /*  If isShareable we could decide to just wrap the java array and
+        share it, but that means adding a globalref to the java array object
+        For now we just always copy the array's data if isShareable.
+     */
     AutoJavaByteArray ar(env, byteArray);
-    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false);
-    SkAutoUnref aur(stream);
-    if (isShareable) {
-        aur.detach();
-    }
-    return doBuildTileIndex(env, stream, isShareable);
+    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
+    return doBuildTileIndex(env, stream);
 }
 
 static jobject nativeCreateLargeBitmapFromFileDescriptor(JNIEnv* env, jobject clazz,
@@ -603,24 +625,31 @@
 
     jint descriptor = env->GetIntField(fileDescriptor,
                                        gFileDescriptor_descriptor);
-    bool weOwnTheFD = false;
+    SkStream *stream = NULL;
+    struct stat fdStat;
+    int newFD;
+    if (fstat(descriptor, &fdStat) == -1) {
+        doThrowIOE(env, "broken file descriptor");
+        return nullObjectReturn("fstat return -1");
+    }
 
-    if (isShareable) {
-        int newFD = ::dup(descriptor);
-        if (-1 != newFD) {
-            weOwnTheFD = true;
-            descriptor = newFD;
+    if (isShareable &&
+            S_ISREG(fdStat.st_mode) &&
+            (newFD = ::dup(descriptor)) != -1) {
+        SkFDStream* fdStream = new SkFDStream(newFD, true);
+        if (!fdStream->isValid()) {
+            fdStream->unref();
+            return NULL;
         }
-    }
-
-    SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
-    SkAutoUnref aur(stream);
-    if (!stream->isValid()) {
-        return NULL;
-    }
-
-    if (isShareable) {
-        aur.detach();
+        stream = fdStream;
+    } else {
+        SkFDStream* fdStream = new SkFDStream(descriptor, false);
+        if (!fdStream->isValid()) {
+            fdStream->unref();
+            return NULL;
+        }
+        stream = buildSkMemoryStream(fdStream);
+        fdStream->unref();
     }
 
     /* Restore our offset when we leave, so we can be called more than once
@@ -629,7 +658,7 @@
     */
     AutoFDSeek as(descriptor);
 
-    return doBuildTileIndex(env, stream, isShareable);
+    return doBuildTileIndex(env, stream);
 }
 
 static jobject nativeCreateLargeBitmapFromStream(JNIEnv* env, jobject clazz,
@@ -641,7 +670,8 @@
 
     if (stream) {
         // for now we don't allow shareable with java inputstreams
-        largeBitmap = doBuildTileIndex(env, stream, false);
+        SkMemoryStream *mStream = buildSkMemoryStream(stream);
+        largeBitmap = doBuildTileIndex(env, mStream);
         stream->unref();
     }
     return largeBitmap;
@@ -650,14 +680,12 @@
 static jobject nativeCreateLargeBitmapFromAsset(JNIEnv* env, jobject clazz,
                                  jint native_asset, // Asset
                                  jboolean isShareable) {
-    SkStream* stream;
+    SkStream* stream, *assStream;
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
-    stream = new AssetStreamAdaptor(asset);
-    SkAutoUnref aur(stream);
-    if (isShareable) {
-        aur.detach();
-    }
-    return doBuildTileIndex(env, stream, isShareable);
+    assStream = new AssetStreamAdaptor(asset);
+    stream = buildSkMemoryStream(assStream);
+    assStream->unref();
+    return doBuildTileIndex(env, stream);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index 30a73184..c402556 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -30,11 +30,12 @@
             android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="?android:attr/windowActionBarStyle" />
+            style="?android:attr/actionBarStyle" />
         <com.android.internal.widget.ActionBarContextView
             android:id="@+id/action_context_bar"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            style="?android:attr/actionModeStyle" />
     </ViewAnimator>
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
diff --git a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
index cb35ac1..af051ae 100644
--- a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
@@ -34,11 +34,12 @@
             android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="?android:attr/windowActionBarStyle" />
+            style="?android:attr/actionBarStyle" />
         <com.android.internal.widget.ActionBarContextView
             android:id="@+id/action_context_bar"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            style="?android:attr/actionModeStyle" />
     </ViewAnimator>
     <ImageView android:src="?android:attr/windowContentOverlay"
                android:scaleType="fitXY"
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index 3c046fe..3864981 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -22,12 +22,10 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
-        android:ellipsize="end"
-        android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+        android:ellipsize="end" />
     <TextView android:id="@+id/action_bar_subtitle"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
-        android:ellipsize="end"
-        android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+        android:ellipsize="end" />
 </LinearLayout>
diff --git a/core/res/res/layout/action_mode_bar.xml b/core/res/res/layout/action_mode_bar.xml
index acf327e..dc09fdc 100644
--- a/core/res/res/layout/action_mode_bar.xml
+++ b/core/res/res/layout/action_mode_bar.xml
@@ -20,4 +20,5 @@
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
-     android:visibility="gone" />
+     android:visibility="gone"
+     style="?android:attr/actionModeStyle" />
diff --git a/core/res/res/layout/launch_warning.xml b/core/res/res/layout/launch_warning.xml
new file mode 100644
index 0000000..1923ff0
--- /dev/null
+++ b/core/res/res/layout/launch_warning.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 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.
+*/
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="6dp"
+        android:paddingBottom="6dp"
+        android:scaleType="fitXY"
+        android:gravity="fill_horizontal"
+        android:src="@android:drawable/divider_horizontal_dark" />
+            
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="10dip"
+        android:orientation="horizontal">
+        <ImageView android:id="@+id/replace_app_icon"
+            android:layout_width="@android:dimen/app_icon_size"
+            android:layout_height="@android:dimen/app_icon_size"
+            android:scaleType="fitCenter" />
+        <TextView android:id="@+id/replace_message"
+            style="?android:attr/textAppearanceMedium"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="5dip" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="10dip"
+        android:orientation="horizontal">
+        <ImageView android:id="@+id/original_app_icon"
+            android:layout_width="@android:dimen/app_icon_size"
+            android:layout_height="@android:dimen/app_icon_size"
+            android:scaleType="fitCenter" />
+        <TextView android:id="@+id/original_message"
+            style="?android:attr/textAppearanceMedium"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="5dip" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 3c44b8c..b158414 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -30,11 +30,12 @@
             android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="?android:attr/windowActionBarStyle" />
+            style="?android:attr/actionBarStyle" />
         <com.android.internal.widget.ActionBarContextView
             android:id="@+id/action_context_bar"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            style="?android:attr/actionModeStyle" />
     </ViewAnimator>
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent" 
@@ -45,6 +46,6 @@
     <LinearLayout android:id="@+id/lower_action_context_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
-                  style="?android:attr/windowActionBarStyle"
+                  style="?android:attr/actionBarStyle"
                   android:visibility="gone" />
 </LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index c854c6f..92a1ee0 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -34,11 +34,12 @@
             android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="?android:attr/windowActionBarStyle" />
+            style="?android:attr/actionBarStyle" />
         <com.android.internal.widget.ActionBarContextView
             android:id="@+id/action_context_bar"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            style="?android:attr/actionModeStyle" />
     </ViewAnimator>
     <ImageView android:src="?android:attr/windowContentOverlay"
                android:scaleType="fitXY"
@@ -49,6 +50,6 @@
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:layout_gravity="bottom"
-                  style="?android:attr/windowActionBarStyle"
+                  style="?android:attr/actionBarStyle"
                   android:visibility="gone" />
 </RelativeLayout>
diff --git a/core/res/res/values-mcc450-ko/config.xml b/core/res/res/values-mcc450-ko/config.xml
new file mode 100644
index 0000000..335b967
--- /dev/null
+++ b/core/res/res/values-mcc450-ko/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<resources>
+    <string name="gsm_alphabet_default_charset">euc-kr</string>
+</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f466e82..7d54ea1 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -267,15 +267,6 @@
              have an Action Bar. -->
         <attr name="windowActionBarOverlay" format="boolean" />
 
-        <!-- Reference to a style for the Action Bar -->
-        <attr name="windowActionBarStyle" format="reference" />
-
-        <!-- Size of the Action Bar, including the contextual
-             bar used to present Action Modes. -->
-        <attr name="windowActionBarSize" format="dimension" >
-            <enum name="wrap_content" value="0" />
-        </attr>
-
         <!-- Flag indicating whether action modes should overlay window content
              when there is not reserved space for their UI (such as an Action Bar). -->
         <attr name="windowActionModeOverlay" format="boolean" />
@@ -478,6 +469,15 @@
         <attr name="actionBarTabBarStyle" format="reference" />
         <attr name="actionBarTabTextStyle" format="reference" />
         <attr name="actionOverflowButtonStyle" format="reference" />
+        <attr name="actionModeStyle" format="reference" />
+        <!-- Reference to a style for the Action Bar -->
+        <attr name="actionBarStyle" format="reference" />
+        <!-- Size of the Action Bar, including the contextual
+             bar used to present Action Modes. -->
+        <attr name="actionBarSize" format="dimension" >
+            <enum name="wrap_content" value="0" />
+        </attr>
+
 
         <!-- =================== -->
         <!-- Action mode styles  -->
@@ -1027,10 +1027,8 @@
         <attr name="backgroundDimEnabled" />
         <attr name="backgroundDimAmount" />
         <attr name="windowActionBar" />
-        <attr name="windowActionBarStyle" />
         <attr name="windowActionModeOverlay" />
         <attr name="windowActionBarOverlay" />
-        <attr name="windowActionBarSize" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -4081,4 +4079,19 @@
         <attr name="height" />
     </declare-styleable>
 
+    <declare-styleable name="ActionMode">
+        <!-- Specifies a style to use for title text. -->
+        <attr name="titleTextStyle" />
+        <!-- Specifies a style to use for subtitle text. -->
+        <attr name="subtitleTextStyle" />
+        <!-- Specifies a background for the action mode bar. -->
+        <attr name="background" />
+        <!-- Specifies a fixed height for the action mode bar. -->
+        <attr name="height" />
+        <!-- Specifies a padding to use between elements on the bar. -->
+        <attr name="itemPadding" format="dimension" />
+        <!-- Specifies a style for the mode's close button. -->
+        <attr name="closeButtonStyle" format="reference" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dbfba2e..ac5828f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -405,4 +405,8 @@
 
     <!-- IP address of the dns server to use if nobody else suggests one -->
     <string name="config_default_dns_server">8.8.8.8</string>
+
+    <!-- The default character set for GsmAlphabet -->
+    <!-- Empty string means MBCS is not considered -->
+    <string name="gsm_alphabet_default_charset"></string>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7f168a1..bff22a6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1299,7 +1299,7 @@
   <public type="attr" name="withClass" />
   <public type="attr" name="allContactsName" />
   <public type="attr" name="windowActionBar" />
-  <public type="attr" name="windowActionBarStyle" />
+  <public type="attr" name="actionBarStyle" />
   <public type="attr" name="navigationMode" />
   <public type="attr" name="displayOptions" />
   <public type="attr" name="subtitle" />
@@ -1327,7 +1327,7 @@
   <public type="attr" name="fragmentOpenExitAnimation" />
   <public type="attr" name="fragmentCloseEnterAnimation" />
   <public type="attr" name="fragmentCloseExitAnimation" />
-  <public type="attr" name="windowActionBarSize" />
+  <public type="attr" name="actionBarSize" />
   <public type="attr" name="imeSubtypeLocale" />
   <public type="attr" name="imeSubtypeMode" />
   <public type="attr" name="imeSubtypeExtraValue" />
@@ -1339,6 +1339,10 @@
   <public type="attr" name="actionBarTabBarStyle" />
   <public type="attr" name="actionBarTabTextStyle" />
   <public type="attr" name="actionOverflowButtonStyle" />
+  <public type="attr" name="itemPadding" />
+  <public type="attr" name="closeButtonStyle" />
+  <public type="attr" name="titleTextStyle" />
+  <public type="attr" name="subtitleTextStyle" />
 
   <public type="anim" name="animator_fade_in" />
   <public type="anim" name="animator_fade_out" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1981ac0..1ebb085 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1951,6 +1951,12 @@
     <string name="report">Report</string>
     <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. -->
     <string name="wait">Wait</string>
+    <!-- [CHAR LIMIT=25] Title of the alert when application launches on top of another. -->
+    <string name="launch_warning_title">Application redirected</string>
+    <!-- [CHAR LIMIT=50] Title of the alert when application launches on top of another. -->
+    <string name="launch_warning_replace"><xliff:g id="app_name">%1$s</xliff:g> is now running.</string>
+    <!-- [CHAR LIMIT=50] Title of the alert when application launches on top of another. -->
+    <string name="launch_warning_original"><xliff:g id="app_name">%1$s</xliff:g> was originally launched.</string>
 
     <!-- Text of the alert that is displayed when an application has violated StrictMode. -->
     <string name="smv_application">The application <xliff:g id="application">%1$s</xliff:g>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5c3870d..fa5c70b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -879,15 +879,42 @@
         <item name="android:background">@android:drawable/bottom_bar</item>
     </style>
 
-    <style name="ActionBar">
+    <style name="Widget.ActionBar">
         <item name="android:background">@android:drawable/action_bar_background</item>
         <item name="android:displayOptions">useLogo</item>
         <item name="android:divider">@android:drawable/action_bar_divider</item>
-        <item name="android:height">?android:attr/windowActionBarSize</item>
+        <item name="android:height">?android:attr/actionBarSize</item>
         <item name="android:paddingLeft">3dip</item>
         <item name="android:paddingTop">0dip</item>
         <item name="android:paddingRight">3dip</item>
         <item name="android:paddingBottom">0dip</item>
+        <item name="android:titleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Title</item>
+        <item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Subtitle</item>
+    </style>
+
+    <style name="Widget.ActionMode">
+        <item name="android:background">?android:attr/actionModeBackground</item>
+        <item name="android:height">?android:attr/actionBarSize</item>
+        <item name="android:itemPadding">?android:attr/actionButtonPadding</item>
+        <item name="android:closeButtonStyle">@android:style/Widget.ActionButton.CloseMode</item>
+        <item name="android:titleTextStyle">@android:style/TextAppearance.Widget.ActionMode.Title</item>
+        <item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionMode.Subtitle</item>
+    </style>
+
+    <style name="TextAppearance.Widget.ActionBar.Title"
+           parent="@android:style/TextAppearance.Medium.Inverse">
+    </style>
+
+    <style name="TextAppearance.Widget.ActionBar.Subtitle"
+           parent="@android:style/TextAppearance.Small.Inverse">
+    </style>
+
+    <style name="TextAppearance.Widget.ActionMode.Title"
+           parent="@android:style/TextAppearance.Medium.Inverse">
+    </style>
+
+    <style name="TextAppearance.Widget.ActionMode.Subtitle"
+           parent="@android:style/TextAppearance.Small.Inverse">
     </style>
 
     <style name="Widget.ActionButton">
@@ -899,6 +926,10 @@
         <item name="android:contentDescription">@string/more_item_label</item>
     </style>
 
+    <style name="Widget.ActionButton.CloseMode">
+        <item name="android:src">?android:attr/actionModeCloseDrawable</item>
+    </style>
+
     <style name="Widget.ActionBarView_TabView">
         <item name="android:background">@drawable/minitab_lt</item>
         <item name="android:paddingLeft">4dip</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7b3a47c..e66e52a 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -126,8 +126,6 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
         <item name="windowActionBar">false</item>
         <item name="windowActionModeOverlay">false</item>
-        <item name="windowActionBarStyle">@android:style/ActionBar</item>
-        <item name="windowActionBarSize">50dip</item>
 
         <!-- Dialog attributes -->
         <item name="alertDialogStyle">@android:style/AlertDialog</item>
@@ -200,9 +198,6 @@
         <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.QuickContactBadgeSmall.WindowSmall</item>
         <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.QuickContactBadgeSmall.WindowMedium</item>
         <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.QuickContactBadgeSmall.WindowLarge</item>
-        <item name="actionBarTabStyle">@style/Widget.ActionBarView_TabView</item>
-        <item name="actionBarTabBarStyle">@style/Widget.ActionBarView_TabBar</item>
-        <item name="actionBarTabTextStyle">@style/Widget.ActionBarView_TabText</item>
         
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
@@ -223,6 +218,12 @@
         <item name="actionButtonPadding">12dip</item>
         <item name="actionModeBackground">@android:drawable/action_bar_context_background</item>
         <item name="actionModeCloseDrawable">@android:drawable/ic_menu_close_clear_cancel</item>
+        <item name="actionBarTabStyle">@style/Widget.ActionBarView_TabView</item>
+        <item name="actionBarTabBarStyle">@style/Widget.ActionBarView_TabBar</item>
+        <item name="actionBarTabTextStyle">@style/Widget.ActionBarView_TabText</item>
+        <item name="actionModeStyle">@style/Widget.ActionMode</item>
+        <item name="actionBarStyle">@android:style/Widget.ActionBar</item>
+        <item name="actionBarSize">50dip</item>
     </style>
     
     <!-- Variant of the default (dark) theme with no title bar -->
@@ -566,6 +567,13 @@
         <item name="android:textColor">@android:color/secondary_text_nofocus</item>
     </style>
 
+    <!-- Default theme for window that looks like a toast. -->
+    <style name="Theme.Toast" parent="@android:style/Theme.Dialog">
+        <item name="android:windowBackground">@android:drawable/toast_frame</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Toast</item>
+        <item name="android:backgroundDimEnabled">false</item>
+    </style>
+
     <!-- Default theme with an Action Bar. -->
     <style name="Theme.WithActionBar">
         <item name="android:windowActionBar">true</item>
@@ -601,7 +609,7 @@
         <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_light</item>
         <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_light</item>
     </style>
-
+        
     <!-- Variant of the holographic (dark) theme with no action bar. -->
     <style name="Theme.Holo.NoActionBar">
         <item name="android:windowActionBar">false</item>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 9d6c3ab..4594bb5 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -101,7 +101,7 @@
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
-ADT 0.9.8</a> <em>(August 2010)</em>
+ADT 0.9.8</a> <em>(September 2010)</em>
   <div class="toggleme">
 
 
diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd
index dc58801..0f075e5 100644
--- a/docs/html/sdk/tools-notes.jd
+++ b/docs/html/sdk/tools-notes.jd
@@ -127,7 +127,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
 SDK Tools, Revision 5</a> <em>(March 2010)</em>
   <div class="toggleme">
 
diff --git a/drm/common/Android.mk b/drm/common/Android.mk
new file mode 100644
index 0000000..249fe8e
--- /dev/null
+++ b/drm/common/Android.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+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
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/common/DrmConstraints.cpp b/drm/common/DrmConstraints.cpp
new file mode 100644
index 0000000..11ce410
--- /dev/null
+++ b/drm/common/DrmConstraints.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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) {
+    LOGV("DrmConstraints::KeyIterator::KeyIterator");
+}
+
+DrmConstraints::KeyIterator& DrmConstraints::KeyIterator::operator=(
+    const DrmConstraints::KeyIterator& keyIterator) {
+    LOGV("DrmConstraints::KeyIterator::operator=");
+    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) {
+    LOGV("DrmConstraints::Iterator::Iterator");
+}
+
+DrmConstraints::Iterator& DrmConstraints::Iterator::operator=(
+    const DrmConstraints::Iterator& iterator) {
+    LOGV("DrmConstraints::Iterator::operator=");
+    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/drm/common/DrmConvertedStatus.cpp b/drm/common/DrmConvertedStatus.cpp
new file mode 100644
index 0000000..5d035f5
--- /dev/null
+++ b/drm/common/DrmConvertedStatus.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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/DrmConvertedStatus.h>
+
+using namespace android;
+
+DrmConvertedStatus::DrmConvertedStatus(
+    int _statusCode, const DrmBuffer* _convertedData, int _offset) :
+    statusCode(_statusCode),
+    convertedData(_convertedData),
+    offset(_offset) {
+
+}
+
diff --git a/drm/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
new file mode 100644
index 0000000..70398e8
--- /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);
+}
+
+void 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);
+}
+
+void DrmEngineBase::consumeRights(
+    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    onConsumeRights(uniqueId, decryptHandle, action, reserve);
+}
+
+void DrmEngineBase::setPlaybackStatus(
+    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+}
+
+bool DrmEngineBase::validateAction(
+    int uniqueId, const String8& path,
+    int action, const ActionDescription& description) {
+    return onValidateAction(uniqueId, path, action, description);
+}
+
+void DrmEngineBase::removeRights(int uniqueId, const String8& path) {
+    onRemoveRights(uniqueId, path);
+}
+
+void DrmEngineBase::removeAllRights(int uniqueId) {
+    onRemoveAllRights(uniqueId);
+}
+
+void DrmEngineBase::openConvertSession(int uniqueId, int convertId) {
+    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);
+}
+
+void DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    onCloseDecryptSession(uniqueId, decryptHandle);
+}
+
+void DrmEngineBase::initializeDecryptUnit(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
+}
+
+status_t DrmEngineBase::decrypt(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+}
+
+void DrmEngineBase::finalizeDecryptUnit(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    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..eb58129
--- /dev/null
+++ b/drm/common/DrmInfoEvent.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "DrmInfoEvent"
+#include "utils/Log.h"
+
+#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/drm/common/DrmInfoStatus.cpp b/drm/common/DrmInfoStatus.cpp
new file mode 100644
index 0000000..f3a1516
--- /dev/null
+++ b/drm/common/DrmInfoStatus.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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/DrmInfoStatus.h>
+
+using namespace android;
+
+DrmInfoStatus::DrmInfoStatus(
+    int _statusCode, const DrmBuffer* _drmBuffer, const String8& _mimeType) :
+    statusCode(_statusCode),
+    drmBuffer(_drmBuffer),
+    mimeType(_mimeType) {
+
+}
+
diff --git a/drm/common/DrmRights.cpp b/drm/common/DrmRights.cpp
new file mode 100644
index 0000000..dc1e6c5
--- /dev/null
+++ b/drm/common/DrmRights.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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>
+
+using namespace android;
+
+DrmRights::DrmRights(const String8& rightsFilePath, const String8& mimeType,
+            const String8& accountId, const String8& subscriptionId) {
+    /**
+     * TODO Read DrmRights from rights file
+     */
+}
+
+DrmRights::DrmRights(const DrmBuffer& rightsData, const String8& mimeType,
+            const String8& accountId, const String8& subscriptionId) :
+    mData(rightsData),
+    mMimeType(mimeType),
+    mAccountId(accountId),
+    mSubscriptionId(subscriptionId) {
+}
+
+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..35e83fc
--- /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 (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 (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..7ce45e7
--- /dev/null
+++ b/drm/common/IDrmIOService.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "IDrmIOService"
+#include <utils/Log.h>
+
+#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..4fc828a
--- /dev/null
+++ b/drm/common/IDrmManagerService.cpp
@@ -0,0 +1,1358 @@
+/*
+ * 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;
+
+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;
+}
+
+void 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);
+}
+
+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();
+}
+
+void 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);
+}
+
+void 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);
+}
+
+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());
+}
+
+void 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);
+}
+
+void BpDrmManagerService::removeAllRights(int uniqueId) {
+    LOGV("removeAllRights");
+    Parcel data, reply;
+
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    remote()->transact(REMOVE_ALL_RIGHTS, data, &reply);
+}
+
+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();
+    LOGV("BpDrmManagerService::openDecryptSession: InterfaceDescriptor name is %s",
+        interfaceDescriptor.string());
+    data.writeInterfaceToken(interfaceDescriptor);
+    data.writeInt32(uniqueId);
+    data.writeFileDescriptor(fd);
+    data.writeInt32(offset);
+    data.writeInt32(length);
+
+    LOGV("try to invoke remote onTransact() with code OPEN_DECRYPT_SESSION");
+    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;
+}
+
+void 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;
+}
+
+void 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);
+}
+
+status_t BpDrmManagerService::decrypt(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    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);
+
+    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;
+}
+
+void 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);
+}
+
+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 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);
+
+        status_t status = unloadPlugIns(data.readInt32());
+
+        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));
+
+        saveRights(uniqueId, drmRights,
+                            ((rightsPath == String8("NULL")) ? String8("") : rightsPath),
+                            ((contentPath == String8("NULL")) ? String8("") : contentPath));
+
+        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;
+        }
+
+        consumeRights(uniqueId, &handle, data.readInt32(), static_cast<bool>(data.readInt32()));
+
+        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;
+        }
+
+        setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+
+        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);
+
+        removeRights(data.readInt32(), data.readString8());
+
+        return DRM_NO_ERROR;
+    }
+
+    case REMOVE_ALL_RIGHTS:
+    {
+        LOGV("BnDrmManagerService::onTransact :REMOVE_ALL_RIGHTS");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        removeAllRights(data.readInt32());
+
+        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;
+        }
+
+        closeDecryptSession(uniqueId, handle);
+        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);
+
+        initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+
+        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);
+
+        const status_t status = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer);
+
+        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;
+        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;
+        }
+
+        finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+
+        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..0a69115
--- /dev/null
+++ b/drm/common/IDrmServiceListener.cpp
@@ -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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "IDrmServiceListener"
+#include <utils/Log.h>
+
+#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..4319c1c
--- /dev/null
+++ b/drm/common/ReadWriteUtils.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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 <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/FileMap.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) {
+            FileMap* fileMap = new FileMap();
+            if (fileMap->create(filePath.string(), fd, 0, sb.st_size, true)) {
+                char* addr = (char*)fileMap->getDataPtr();
+                string.append(addr, sb.st_size);
+                fileMap->release();
+            }
+        }
+        fclose(file);
+    }
+    return string;
+}
+
+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)) {
+            FileMap* fileMap = NULL;
+            fileMap = new FileMap();
+            if (fileMap->create(filePath.string(), fd, 0, size, false)) {
+                char* addr = (char*)fileMap->getDataPtr();
+                memcpy(addr, data.string(), size);
+                fileMap->release();
+            }
+        }
+        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 offset = lseek(fd, 0, SEEK_END);
+        if (FAILURE != offset) {
+            int newEntrySize = data.size();
+            int fileSize = offset + newEntrySize;
+
+            if (FAILURE != ftruncate(fd, fileSize)) {
+                FileMap* fileMap = NULL;
+                fileMap = new FileMap();
+                if (fileMap->create(filePath.string(), fd, offset, fileSize, false)) {
+                    char* addr = (char*)fileMap->getDataPtr();
+                    memcpy(addr, data.string(), data.size());
+                    fileMap->release();
+                }
+            }
+        }
+        fclose(file);
+    }
+}
+
diff --git a/drm/drmioserver/Android.mk b/drm/drmioserver/Android.mk
new file mode 100644
index 0000000..c40ce26
--- /dev/null
+++ b/drm/drmioserver/Android.mk
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    main_drmioserver.cpp \
+    DrmIOService.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    libbinder \
+    libdl
+
+LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/include
+
+LOCAL_MODULE:= drmioserver
+
+include $(BUILD_EXECUTABLE)
diff --git a/drm/drmioserver/DrmIOService.cpp b/drm/drmioserver/DrmIOService.cpp
new file mode 100644
index 0000000..67cfd39
--- /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..7ed048d6
--- /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..d2ebe8e
--- /dev/null
+++ b/drm/drmserver/Android.mk
@@ -0,0 +1,39 @@
+#
+# 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 \
+    libdl
+
+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
+
+include $(BUILD_EXECUTABLE)
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
new file mode 100644
index 0000000..44886f9
--- /dev/null
+++ b/drm/drmserver/DrmManager.cpp
@@ -0,0 +1,473 @@
+/*
+ * 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;
+
+const String8 DrmManager::EMPTY_STRING("");
+
+DrmManager::DrmManager() :
+    mDecryptSessionId(0),
+    mConvertId(0) {
+
+}
+
+DrmManager::~DrmManager() {
+
+}
+
+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);
+    }
+
+    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;
+}
+
+void DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
+    }
+}
+
+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;
+}
+
+void DrmManager::consumeRights(
+    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
+    }
+}
+
+void DrmManager::setPlaybackStatus(
+    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+    }
+}
+
+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;
+}
+
+void DrmManager::removeRights(int uniqueId, const String8& path) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        rDrmEngine.removeRights(uniqueId, path);
+    }
+}
+
+void DrmManager::removeAllRights(int uniqueId) {
+    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
+
+    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
+        rDrmEngine.removeAllRights(uniqueId);
+    }
+}
+
+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);
+
+        Mutex::Autolock _l(mConvertLock);
+        ++mConvertId;
+        convertId = mConvertId;
+        mConvertSessionMap.add(mConvertId, &rDrmEngine);
+
+        rDrmEngine.openConvertSession(uniqueId, mConvertId);
+    }
+    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) {
+    LOGV("Entering DrmManager::openDecryptSession");
+    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);
+
+            LOGV("plug-in %s return value = %d", plugInId.string(), result);
+
+            if (DRM_NO_ERROR == result) {
+                ++mDecryptSessionId;
+                mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                LOGV("plug-in %s is selected", plugInId.string());
+                break;
+            }
+        }
+    }
+
+    if (DRM_ERROR_CANNOT_HANDLE == result) {
+        delete handle; handle = NULL;
+        LOGE("DrmManager::openDecryptSession: no capable plug-in found");
+    }
+
+    return handle;
+}
+
+void DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        drmEngine->closeDecryptSession(uniqueId, decryptHandle);
+
+        mDecryptSessionMap.removeItem(decryptHandle->decryptId);
+    }
+}
+
+void DrmManager::initializeDecryptUnit(
+    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
+    }
+}
+
+status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        status = drmEngine->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+    }
+    return status;
+}
+
+void DrmManager::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
+        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
+        drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+    }
+}
+
+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..9d000e9
--- /dev/null
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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
+
+void DrmManagerService::instantiate() {
+    LOGV("instantiate");
+
+    int res = mkdir("/data/drm/plugins", DRM_DIRECTORY_PERMISSION);

+    if (SUCCESS == res || EEXIST == errno) {

+        res = mkdir("/data/drm/plugins/native", DRM_DIRECTORY_PERMISSION);

+        if (SUCCESS == res || EEXIST == errno) {

+            res = mkdir("/data/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;
+}
+
+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);
+}
+
+void 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);
+}
+
+void DrmManagerService::consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    LOGV("Entering consumeRights");
+    mDrmManager->consumeRights(uniqueId, decryptHandle, action, reserve);
+}
+
+void DrmManagerService::setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    LOGV("Entering setPlaybackStatus");
+    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);
+}
+
+void DrmManagerService::removeRights(int uniqueId, const String8& path) {
+    LOGV("Entering removeRights");
+    mDrmManager->removeRights(uniqueId, path);
+}
+
+void DrmManagerService::removeAllRights(int uniqueId) {
+    LOGV("Entering removeAllRights");
+    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);
+}
+
+void DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    LOGV("Entering closeDecryptSession");
+    mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
+}
+
+void DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    LOGV("Entering initializeDecryptUnit");
+    mDrmManager->initializeDecryptUnit(uniqueId,decryptHandle, decryptUnitId, headerInfo);
+}
+
+status_t DrmManagerService::decrypt(
+            int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    LOGV("Entering decrypt");
+    return mDrmManager->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+}
+
+void DrmManagerService::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    LOGV("Entering finalizeDecryptUnit");
+    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..367c9bd
--- /dev/null
+++ b/drm/drmserver/StringTokenizer.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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) {
+    LOGV("StringTokenizer::Iterator::Iterator");
+}
+
+StringTokenizer::Iterator& StringTokenizer::Iterator::operator=(
+            const StringTokenizer::Iterator& iterator) {
+    LOGV("StringTokenizer::Iterator::operator=");
+    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/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
new file mode 100644
index 0000000..44c4b43
--- /dev/null
+++ b/drm/java/android/drm/DrmEvent.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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 {
+    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..be1b009
--- /dev/null
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -0,0 +1,77 @@
+/*
+ * 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 = 0x0000001;
+    /**
+     * TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
+     */
+    public static final int TYPE_REMOVE_RIGHTS = 0x0000002;
+    /**
+     * TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
+     */
+    public static final int TYPE_RIGHTS_INSTALLED = 0x0000003;
+    /**
+     * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights.
+     */
+    public static final int TYPE_RIGHTS_NOT_INSTALLED = 0x0000004;
+    /**
+     * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights.
+     */
+    public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 0x0000005;
+    /**
+     * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent.
+     */
+    public static final int TYPE_NOT_SUPPORTED = 0x0000006;
+    /**
+     * 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 = 0x0000007;
+    /**
+     * 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 = 0x0000008;
+    /**
+     * 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 = 0x0000009;
+
+    /**
+     * 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..9ee597c
--- /dev/null
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -0,0 +1,487 @@
+/*
+ * 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.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Interface of DRM Framework.
+ * Java application will instantiate this class
+ * to access DRM agent through DRM Framework.
+ *
+ */
+public class DrmManagerClient {
+    private static final String TAG = "DrmManager";
+
+    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);
+    }
+
+    private static final int STATE_UNINITIALIZED = 0x00000000;
+    private static final int STATE_INITIALIZED = 0x00000001;
+
+    private int mUniqueId;
+    private int mNativeContext;
+    private EventHandler mEventHandler;
+    private OnInfoListener mOnInfoListener;
+    private int mCurrentState = STATE_UNINITIALIZED;
+
+    /**
+     * {@hide}
+     */
+    public static void notify(Object thisReference, int uniqueId, int infoType, String message) {
+        DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
+
+        if (null != instance && null != instance.mEventHandler) {
+            Message m = instance.mEventHandler.obtainMessage(
+                EventHandler.INFO_EVENT_TYPE, uniqueId, infoType, message);
+            instance.mEventHandler.sendMessage(m);
+        }
+    }
+
+    private class EventHandler extends Handler {
+        public static final int INFO_EVENT_TYPE = 1;
+
+        public EventHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void handleMessage(Message msg) {
+
+            switch (msg.what) {
+            case EventHandler.INFO_EVENT_TYPE:
+                int uniqueId = msg.arg1;
+                int infoType = msg.arg2;
+                String message = msg.obj.toString();
+
+                if (infoType == DrmInfoEvent.TYPE_REMOVE_RIGHTS) {
+                    try {
+                        DrmUtils.removeFile(message);
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+
+                if (null != mOnInfoListener) {
+                    DrmInfoEvent event = new DrmInfoEvent(uniqueId, infoType, message);
+                    mOnInfoListener.onInfo(DrmManagerClient.this, event);
+                }
+                return;
+            default:
+                Log.e(TAG, "Unknown message type " + msg.what);
+                return;
+            }
+        }
+    }
+
+    /**
+     * To instantiate DrmManagerClient
+     *
+     * @param context context of the caller
+     */
+    public DrmManagerClient(Context context) {
+        Looper looper;
+
+        if (null != (looper = Looper.myLooper())) {
+            mEventHandler = new EventHandler(looper);
+        } else if (null != (looper = Looper.getMainLooper())) {
+            mEventHandler = new EventHandler(looper);
+        } else {
+            mEventHandler = null;
+        }
+
+        // save the unique id
+        mUniqueId = hashCode();
+    }
+
+    /**
+     * Register a callback to be invoked when the caller required to receive
+     * necessary information
+     *
+     * @param infoListener
+     */
+    public void setOnInfoListener(OnInfoListener infoListener) {
+        synchronized(this) {
+            if (null != infoListener) {
+                mOnInfoListener = infoListener;
+            }
+        }
+    }
+
+    /**
+     * Initializes DrmFramework, which loads all available plug-ins
+     * in the default plug-in directory path
+     *
+     */
+    public void loadPlugIns() {
+        if (getState() == STATE_UNINITIALIZED) {
+            _loadPlugIns(mUniqueId, new WeakReference<DrmManagerClient>(this));
+
+            mCurrentState = STATE_INITIALIZED;
+        }
+    }
+
+    /**
+     * Finalize DrmFramework, which release resources associated with each plug-in
+     * and unload all plug-ins.
+     */
+    public void unloadPlugIns() {
+        if (getState() == STATE_INITIALIZED) {
+            _unloadPlugIns(mUniqueId);
+
+            mCurrentState = STATE_UNINITIALIZED;
+        }
+    }
+
+    /**
+     * Retrieves informations about all the plug-ins registered with DrmFramework.
+     *
+     * @return Array of DrmEngine plug-in strings
+     */
+    public String[] getAvailableDrmEngines() {
+        if (getState() == STATE_UNINITIALIZED) {
+            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 (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _getConstraints(mUniqueId, path, action);
+    }
+
+    /**
+     * Save DRM rights to specified rights path
+     * and make association with content path.
+     *
+     * @param drmRights DrmRights to be saved
+     * @param rightsPath File path where rights to be saved
+     * @param contentPath File path where content was saved
+     * @throws IOException if failed to save rights information in the given path
+     *
+     * @note In case of OMA or WM-DRM, rightsPath and contentPath could be null
+     */
+    public void saveRights(
+            DrmRights drmRights, String rightsPath, String contentPath) throws IOException {
+        if (null == drmRights || !drmRights.isValid()
+            || null == contentPath || contentPath.equals("")) {
+            throw new IllegalArgumentException("Given drmRights or contentPath is not valid");
+        } else if (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        if (null != rightsPath && !rightsPath.equals("")) {
+            DrmUtils.writeToFile(rightsPath, drmRights.getData());
+        }
+        _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 (getState() == STATE_UNINITIALIZED) {
+            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.
+     * @note 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 (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _canHandle(mUniqueId, path, mimeType);
+    }
+
+    /**
+     * Executes given drm information based on its type
+     *
+     * @param drmInfo Information needs to be processed
+     * @return DrmInfoStatus Instance as a result of processing given input
+     */
+    public DrmInfoStatus processDrmInfo(DrmInfo drmInfo) {
+        if (null == drmInfo || !drmInfo.isValid()) {
+            throw new IllegalArgumentException("Given drmInfo is invalid/null");
+        } else if (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _processDrmInfo(mUniqueId, drmInfo);
+    }
+
+    /**
+     * Retrieves necessary information for register, unregister or rights acquisition.
+     *
+     * @param drmInfoRequest Request information to retrieve drmInfo
+     * @return DrmInfo Instance as a result of processing given input
+     */
+    public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
+        if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
+            throw new IllegalArgumentException("Given drmInfoRequest is invalid/null");
+        } else if (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _acquireDrmInfo(mUniqueId, drmInfoRequest);
+    }
+
+    /**
+     * 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 (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _getDrmObjectType(mUniqueId, 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 (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _getOriginalMimeType(mUniqueId, path);
+    }
+
+    /**
+     * 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 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 (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _checkRightsStatus(mUniqueId, path, action);
+    }
+
+    /**
+     * Removes the rights associated with the given protected content
+     *
+     * @param path Path of the protected content
+     */
+    public void removeRights(String path) {
+        if (null == path || path.equals("")) {
+            throw new IllegalArgumentException("Given path should be non null");
+        } else if (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        _removeRights(mUniqueId, path);
+    }
+
+    /**
+     * Removes all the rights information of every plug-in associated with
+     * DRM framework. Will be used in master reset
+     */
+    public void removeAllRights() {
+        if (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        _removeAllRights(mUniqueId);
+    }
+
+    /**
+     * 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 (getState() == STATE_UNINITIALIZED) {
+            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 (getState() == STATE_UNINITIALIZED) {
+            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 (getState() == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Not Initialized yet");
+        }
+        return _closeConvertSession(mUniqueId, convertId);
+    }
+
+    private int getState() {
+        return mCurrentState;
+    }
+
+    // private native interfaces
+    private native void _loadPlugIns(int uniqueId, Object weak_this);
+
+    private native void _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 void _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 void _removeRights(int uniqueId, String path);
+
+    private native void _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..0731755
--- /dev/null
+++ b/drm/jni/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:= \
+    android_drm_DrmManagerClient.cpp
+
+LOCAL_MODULE:= libdrmframework_jni
+
+LOCAL_SHARED_LIBRARIES := \
+    libdrmframework \
+    libutils \
+    libandroid_runtime \
+    libnativehelper \
+    libbinder \
+    libdl
+
+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
+
+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..bc5a7bf
--- /dev/null
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -0,0 +1,755 @@
+/*
+ * 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 {
+            LOGD("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 void 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);
+
+    getDrmManagerClientImpl(env, thiz)->loadPlugIns(uniqueId);
+    LOGV("load plugins - Exit");
+}
+
+static void android_drm_DrmManagerClient_unloadPlugIns(JNIEnv* env, jobject thiz, jint uniqueId) {
+    LOGV("unload plugins - Enter");
+    sp<DrmManagerClientImpl> client = getDrmManagerClientImpl(env, thiz);
+    client->unloadPlugIns(uniqueId);
+    client->setOnInfoListener(uniqueId, NULL);
+    DrmManagerClientImpl::remove(uniqueId);
+
+    sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
+    if (oldClient != NULL) {
+        oldClient->setOnInfoListener(uniqueId, NULL);
+    }
+
+    LOGV("unload plugins - Exit");
+}
+
+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 void android_drm_DrmManagerClient_saveRights(
+            JNIEnv* env, jobject thiz, jint uniqueId,
+            jobject drmRights, jstring rightsPath, jstring contentPath) {
+    LOGV("saveRights - Enter");
+    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"));
+        getDrmManagerClientImpl(env, thiz)
+            ->saveRights(uniqueId, rights, Utility::getStringValue(env, rightsPath),
+                                Utility::getStringValue(env, contentPath));
+    }
+
+    delete mData; mData = NULL;
+    LOGV("saveRights - Exit");
+}
+
+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);
+        LOGD("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);
+        LOGD("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 void android_drm_DrmManagerClient_removeRights(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
+    LOGV("removeRights Enter");
+    getDrmManagerClientImpl(env, thiz)->removeRights(uniqueId, Utility::getStringValue(env, path));
+    LOGV("removeRights Exit");
+}
+
+static void android_drm_DrmManagerClient_removeAllRights(
+            JNIEnv* env, jobject thiz, jint uniqueId) {
+    LOGV("removeAllRights Enter");
+    getDrmManagerClientImpl(env, thiz)->removeAllRights(uniqueId);
+    LOGV("removeAllRights Exit");
+}
+
+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;)V",
+                                    (void*)android_drm_DrmManagerClient_loadPlugIns},
+
+    {"_unloadPlugIns", "(I)V",
+                                    (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;)V",
+                                    (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;)V",
+                                    (void*)android_drm_DrmManagerClient_removeRights},
+
+    {"_removeAllRights", "(I)V",
+                                    (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..c25d79b
--- /dev/null
+++ b/drm/libdrmframework/Android.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    DrmManagerClientImpl.cpp \
+    DrmManagerClient.cpp
+
+LOCAL_MODULE:= libdrmframework
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    libbinder \
+    libdl
+
+LOCAL_STATIC_LIBRARIES := \
+    libdrmframeworkcommon
+
+LOCAL_C_INCLUDES += \
+    $(TOP)/frameworks/base/drm/libdrmframework/include \
+    $(TOP)/frameworks/base/include
+
+LOCAL_PRELINK_MODULE := false
+
+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..06c7c50
--- /dev/null
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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 "DrmManagerClient(Native)"
+#include <utils/Log.h>
+
+#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() {
+    unloadPlugIns();
+    DrmManagerClientImpl::remove(mUniqueId);
+
+    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);
+}
+
+void 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);
+}
+
+void DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) {
+    mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve);
+}
+
+void DrmManagerClient::setPlaybackStatus(
+            DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    mDrmManagerClientImpl->setPlaybackStatus(mUniqueId, decryptHandle, playbackStatus, position);
+}
+
+bool DrmManagerClient::validateAction(
+            const String8& path, int action, const ActionDescription& description) {
+    return mDrmManagerClientImpl->validateAction(mUniqueId, path, action, description);
+}
+
+void DrmManagerClient::removeRights(const String8& path) {
+    mDrmManagerClientImpl->removeRights(mUniqueId, path);
+}
+
+void DrmManagerClient::removeAllRights() {
+    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);
+}
+
+void DrmManagerClient::closeDecryptSession(DecryptHandle* decryptHandle) {
+    mDrmManagerClientImpl->closeDecryptSession(mUniqueId, decryptHandle);
+}
+
+void DrmManagerClient::initializeDecryptUnit(
+            DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    mDrmManagerClientImpl->initializeDecryptUnit(
+        mUniqueId, decryptHandle, decryptUnitId, headerInfo);
+}
+
+status_t DrmManagerClient::decrypt(
+    DecryptHandle* decryptHandle, int decryptUnitId,
+    const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    return mDrmManagerClientImpl->decrypt(
+            mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+}
+
+void DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) {
+    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..7274b49
--- /dev/null
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -0,0 +1,319 @@
+/*
+ * 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;
+Vector<int> DrmManagerClientImpl::mUniqueIdVector;
+sp<IDrmManagerService> DrmManagerClientImpl::mDrmManagerService;
+const String8 DrmManagerClientImpl::EMPTY_STRING("");
+
+DrmManagerClientImpl* DrmManagerClientImpl::create(int* pUniqueId) {
+    if (0 == *pUniqueId) {
+        int uniqueId = 0;
+        bool foundUniqueId = false;
+        srand(time(NULL));
+
+        while (!foundUniqueId) {
+            const int size = mUniqueIdVector.size();
+            uniqueId = rand() % 100;
+
+            int index = 0;
+            for (; index < size; ++index) {
+                if (mUniqueIdVector.itemAt(index) == uniqueId) {
+                    foundUniqueId = false;
+                    break;
+                }
+            }
+            if (index == size) {
+                foundUniqueId = true;
+            }
+        }
+        *pUniqueId = uniqueId;
+    }
+    mUniqueIdVector.push(*pUniqueId);
+    return new DrmManagerClientImpl();
+}
+
+void DrmManagerClientImpl::remove(int uniqueId) {
+    for (int i = 0; i < mUniqueIdVector.size(); i++) {
+        if (uniqueId == mUniqueIdVector.itemAt(i)) {
+            mUniqueIdVector.removeAt(i);
+            break;
+        }
+    }
+}
+
+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;
+}
+
+void DrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    if (EMPTY_STRING != contentPath) {
+        getDrmManagerService()->saveRights(uniqueId, drmRights, rightsPath, contentPath);
+    }
+}
+
+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;
+}
+
+void DrmManagerClientImpl::consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    if (NULL != decryptHandle) {
+        getDrmManagerService()->consumeRights(uniqueId, decryptHandle, action, reserve);
+    }
+}
+
+void DrmManagerClientImpl::setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+    if (NULL != decryptHandle) {
+        getDrmManagerService()->setPlaybackStatus(
+                uniqueId, decryptHandle, playbackStatus, position);
+    }
+}
+
+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;
+}
+
+void DrmManagerClientImpl::removeRights(int uniqueId, const String8& path) {
+    if (EMPTY_STRING != path) {
+        getDrmManagerService()->removeRights(uniqueId, path);
+    }
+}
+
+void DrmManagerClientImpl::removeAllRights(int uniqueId) {
+    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) {
+    LOGV("Entering DrmManagerClientImpl::openDecryptSession");
+    return getDrmManagerService()->openDecryptSession(uniqueId, fd, offset, length);
+}
+
+void DrmManagerClientImpl::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    if (NULL != decryptHandle) {
+        getDrmManagerService()->closeDecryptSession( uniqueId, decryptHandle);
+    }
+}
+
+void DrmManagerClientImpl::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    if ((NULL != decryptHandle) && (NULL != headerInfo)) {
+        getDrmManagerService()->initializeDecryptUnit(
+                uniqueId, decryptHandle, decryptUnitId, headerInfo);
+    }
+}
+
+status_t DrmManagerClientImpl::decrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    status_t status = DRM_ERROR_UNKNOWN;
+    if ((NULL != decryptHandle) && (NULL != encBuffer)
+        && (NULL != decBuffer) && (NULL != *decBuffer)) {
+        status = getDrmManagerService()->decrypt(
+                uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+    }
+    return status;
+}
+
+void DrmManagerClientImpl::finalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    if (NULL != decryptHandle) {
+        getDrmManagerService()->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+    }
+}
+
+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..2ba9e99
--- /dev/null
+++ b/drm/libdrmframework/include/DrmManager.h
@@ -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.
+ */
+
+#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:
+
+    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);
+
+    void 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);
+
+    void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    void setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    void removeRights(int uniqueId, const String8& path);
+
+    void 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);
+
+    void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer,DrmBuffer** decBuffer);
+
+    void 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 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..e70e6e1
--- /dev/null
+++ b/drm/libdrmframework/include/DrmManagerClientImpl.h
@@ -0,0 +1,400 @@
+/*
+ * 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
+     */
+    void 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.
+     */
+    void 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.
+     */
+    void 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
+     */
+    void 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
+     */
+    void 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
+     */
+    void 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
+     */
+    void 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
+     * @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);
+
+    /**
+     * 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
+     */
+    void 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 Vector<int> mUniqueIdVector;
+    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..fef121c
--- /dev/null
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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:
+    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);
+
+    void 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);
+
+    void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    void setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool validateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description);
+
+    void removeRights(int uniqueId, const String8& path);
+
+    void 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);
+
+    void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+
+    void 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..a4d128a
--- /dev/null
+++ b/drm/libdrmframework/include/IDrmManagerService.h
@@ -0,0 +1,242 @@
+/*
+ * 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 {
+        LOAD_PLUGINS = IBinder::FIRST_CALL_TRANSACTION,
+        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 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 void 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 void consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+
+    virtual void 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 void removeRights(int uniqueId, const String8& path) = 0;
+
+    virtual void 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 void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+
+    virtual void 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) = 0;
+
+    virtual void 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 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 void 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 void consumeRights(
+            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    virtual void setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    virtual bool validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    virtual void removeRights(int uniqueId, const String8& path);
+
+    virtual void 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 void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    virtual void 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);
+
+    virtual void 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..022149ee2
--- /dev/null
+++ b/drm/libdrmframework/include/ReadWriteUtils.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 __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);
+    /**
+     * 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..667958a
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
@@ -0,0 +1,411 @@
+/*
+ * 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);
+
+    void 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);
+
+    void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    void setPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool validateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    void removeRights(int uniqueId, const String8& path);
+
+    void removeAllRights(int uniqueId);
+
+    void 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);
+
+    void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+
+    void 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
+     */
+    virtual void 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.
+     */
+    virtual void 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.
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     * @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) = 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
+     */
+    virtual void 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..0d52f66
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
@@ -0,0 +1,371 @@
+/*
+ * 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
+     */
+    virtual void 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.
+     */
+    virtual void 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.
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     */
+    virtual void 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
+     * @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) = 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
+     */
+    virtual void 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..a7bbf23
--- /dev/null
+++ b/drm/libdrmframework/plugins/passthru/Android.mk
@@ -0,0 +1,44 @@
+#
+# 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 \
+    libdl
+
+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
+
+PRODUCT_COPY_FILES += \
+    $(TARGET_OUT_SHARED_LIBRARIES)/libdrmpassthruplugin.so:system/lib/drm/plugins/native/libdrmpassthruplugin.so
+
+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..d2c7852
--- /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);
+
+    void 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);
+
+    void onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    void onSetPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
+
+    bool onValidateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    void onRemoveRights(int uniqueId, const String8& path);
+
+    void onRemoveAllRights(int uniqueId);
+
+    void 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);
+
+    void onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+     void onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+     status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+
+     void 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..2655d0b
--- /dev/null
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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;
+}
+
+void DrmPassthruPlugIn::onSaveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    LOGD("DrmPassthruPlugIn::onSaveRights : %d", uniqueId);
+}
+
+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;
+}
+
+void DrmPassthruPlugIn::onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+            int action, bool reserve) {
+    LOGD("DrmPassthruPlugIn::onConsumeRights() : %d", uniqueId);
+}
+
+void DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+            int playbackStatus, int position) {
+    LOGD("DrmPassthruPlugIn::onSetPlaybackStatus() : %d", uniqueId);
+}
+
+bool DrmPassthruPlugIn::onValidateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description) {
+    LOGD("DrmPassthruPlugIn::onValidateAction() : %d", uniqueId);
+    return true;
+}
+
+void DrmPassthruPlugIn::onRemoveRights(int uniqueId, const String8& path) {
+    LOGD("DrmPassthruPlugIn::onRemoveRights() : %d", uniqueId);
+}
+
+void DrmPassthruPlugIn::onRemoveAllRights(int uniqueId) {
+    LOGD("DrmPassthruPlugIn::onRemoveAllRights() : %d", uniqueId);
+}
+
+void DrmPassthruPlugIn::onOpenConvertSession(int uniqueId, int convertId) {
+    LOGD("DrmPassthruPlugIn::onOpenConvertSession() : %d", uniqueId);
+}
+
+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;
+}
+
+void 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;
+    }
+}
+
+void DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    LOGD("DrmPassthruPlugIn::onInitializeDecryptUnit() : %d", uniqueId);
+}
+
+status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+    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;
+}
+
+void DrmPassthruPlugIn::onFinalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    LOGD("DrmPassthruPlugIn::onFinalizeDecryptUnit() : %d", uniqueId);
+}
+
+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/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..5e8817c
--- /dev/null
+++ b/include/drm/DrmInfoEvent.h
@@ -0,0 +1,99 @@
+/*
+ * 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:
+    //! 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 = 0x0000001;
+    //! TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
+    static const int TYPE_REMOVE_RIGHTS = 0x0000002;
+    //! TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
+    static const int TYPE_RIGHTS_INSTALLED = 0x0000003;
+    //! TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights
+    static const int TYPE_RIGHTS_NOT_INSTALLED = 0x0000004;
+    //! TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights
+    static const int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 0x0000005;
+    //! TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent
+    static const int TYPE_NOT_SUPPORTED = 0x0000006;
+    //! 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 = 0x0000007;
+    //! 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 = 0x0000008;
+    //! 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 = 0x0000009;
+
+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..7d14c44
--- /dev/null
+++ b/include/drm/DrmManagerClient.h
@@ -0,0 +1,351 @@
+/*
+ * 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
+     */
+    void 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.
+     */
+    void 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.
+     */
+    void 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
+     */
+    void 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
+     * @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);
+
+    /**
+     * 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
+     */
+    void 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
+     */
+    void 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
+     */
+    void removeRights(const String8& path);
+
+    /**
+     * Removes all the rights information of each plug-in associated with
+     * DRM framework. Will be used in master reset
+     *
+     */
+    void 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..e04a066
--- /dev/null
+++ b/include/drm/DrmRights.h
@@ -0,0 +1,105 @@
+/*
+ * 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;
+};
+
+};
+
+#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..8b8a9f5
--- /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)
+     *
+     *         DecryptAPI::TYPE_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)
+     *
+     *         DecryptAPI::TYPE_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/keystore/java/android/security/SystemKeyStore.java b/keystore/java/android/security/SystemKeyStore.java
index abdb0ae..1093219 100644
--- a/keystore/java/android/security/SystemKeyStore.java
+++ b/keystore/java/android/security/SystemKeyStore.java
@@ -20,6 +20,8 @@
 import android.os.FileUtils;
 import android.os.Process;
 
+import org.apache.harmony.luni.util.InputStreamHelper;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -108,26 +110,19 @@
         return keyFile;
     }
 
-    public String retrieveKeyHexString(String keyName) {
+    public String retrieveKeyHexString(String keyName) throws IOException {
         return toHexString(retrieveKey(keyName));
     }
 
-    public byte[] retrieveKey(String keyName) {
-
+    public byte[] retrieveKey(String keyName) throws IOException {
         File keyFile = getKeyFile(keyName);
+
         if (!keyFile.exists()) {
             return null;
         }
 
-        try {
-            FileInputStream fis = new FileInputStream(keyFile);
-            int keyLen = fis.available();
-            byte[] retKey = new byte[keyLen];
-            fis.read(retKey);
-            fis.close();
-            return retKey;
-        } catch (IOException ioe) { }
-        throw new IllegalArgumentException();
+        FileInputStream fis = new FileInputStream(keyFile);
+        return InputStreamHelper.readFullyAndClose(fis);
     }
 
     public void deleteKey(String keyName) {
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 7778290..d50d36e 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -26,17 +26,33 @@
 namespace android {
 namespace uirenderer {
 
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_EXTENSIONS 0
+
+// Debug
+#if DEBUG_EXTENSIONS
+    #define EXT_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define EXT_LOGD(...)
+#endif
+
 class Extensions {
 public:
     Extensions() {
         const char* buffer = (const char*) glGetString(GL_EXTENSIONS);
         const char* current = buffer;
         const char* head = current;
+        EXT_LOGD("Available GL extensions:");
         do {
             head = strchr(current, ' ');
             String8 s(current, head ? head - current : strlen(current));
             if (s.length()) {
                 mExtensionList.add(s);
+                EXT_LOGD("  %s", s.string());
             }
             current = head + 1;
         } while (head);
@@ -44,6 +60,7 @@
         mHasNPot = hasExtension("GL_OES_texture_npot");
         mHasDrawPath = hasExtension("GL_NV_draw_path");
         mHasCoverageSample = hasExtension("GL_NV_coverage_sample");
+        mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
 
         mExtensions = buffer;
     }
@@ -51,6 +68,7 @@
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasDrawPath() const { return mHasDrawPath; }
     inline bool hasCoverageSample() const { return mHasCoverageSample; }
+    inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
 
     bool hasExtension(const char* extension) const {
         const String8 s(extension);
@@ -69,6 +87,7 @@
     bool mHasNPot;
     bool mHasDrawPath;
     bool mHasCoverageSample;
+    bool mHasFramebufferFetch;
 }; // class Extensions
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f70bca7..6c90704 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -240,10 +240,14 @@
 
     if (p) {
         alpha = p->getAlpha();
-        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
-        if (!isMode) {
-            // Assume SRC_OVER
-            mode = SkXfermode::kSrcOver_Mode;
+        if (!mExtensions.hasFramebufferFetch()) {
+            const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
+            if (!isMode) {
+                // Assume SRC_OVER
+                mode = SkXfermode::kSrcOver_Mode;
+            }
+        } else {
+            mode = getXfermode(p->getXfermode());
         }
     } else {
         mode = SkXfermode::kSrcOver_Mode;
@@ -519,11 +523,14 @@
     }
 
     SkXfermode::Mode mode;
-
-    const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
-    if (!isMode) {
-        // Assume SRC_OVER
-        mode = SkXfermode::kSrcOver_Mode;
+    if (!mExtensions.hasFramebufferFetch()) {
+        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
+        if (!isMode) {
+            // Assume SRC_OVER
+            mode = SkXfermode::kSrcOver_Mode;
+        }
+    } else {
+        mode = getXfermode(p->getXfermode());
     }
 
     // Skia draws using the color's alpha channel if < 255
@@ -731,11 +738,12 @@
          }
      }
 
+     // Setup the blending mode
+     chooseBlending(true, mode, description);
+
      // Build and use the appropriate shader
      useProgram(mCaches.programCache.get(description));
 
-     // Setup the blending mode
-     chooseBlending(true, mode);
      bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
      glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit);
 
@@ -837,9 +845,6 @@
 
     GLuint textureUnit = 0;
 
-    // Setup the blending mode
-    chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode);
-
     // Describe the required shaders
     ProgramDescription description;
     if (mShader) {
@@ -849,6 +854,9 @@
         mColorFilter->describe(description, mExtensions);
     }
 
+    // Setup the blending mode
+    chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode, description);
+
     // Build and use the appropriate shader
     useProgram(mCaches.programCache.get(description));
 
@@ -907,11 +915,11 @@
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
 
+    chooseBlending(blend || alpha < 1.0f, mode, description);
+
     useProgram(mCaches.programCache.get(description));
     mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
 
-    chooseBlending(blend || alpha < 1.0f, mode);
-
     // Texture
     bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
     glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
@@ -939,23 +947,35 @@
     glDisableVertexAttribArray(texCoordsSlot);
 }
 
-void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
+void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
+        ProgramDescription& description) {
     blend = blend || mode != SkXfermode::kSrcOver_Mode;
     if (blend) {
-        if (!mCaches.blend) {
-            glEnable(GL_BLEND);
-        }
+        if (mode < SkXfermode::kPlus_Mode) {
+            if (!mCaches.blend) {
+                glEnable(GL_BLEND);
+            }
 
-        GLenum sourceMode = gBlends[mode].src;
-        GLenum destMode = gBlends[mode].dst;
-        if (!isPremultiplied && sourceMode == GL_ONE) {
-            sourceMode = GL_SRC_ALPHA;
-        }
+            GLenum sourceMode = gBlends[mode].src;
+            GLenum destMode = gBlends[mode].dst;
 
-        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
-            glBlendFunc(sourceMode, destMode);
-            mCaches.lastSrcMode = sourceMode;
-            mCaches.lastDstMode = destMode;
+            if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
+                glBlendFunc(sourceMode, destMode);
+                mCaches.lastSrcMode = sourceMode;
+                mCaches.lastDstMode = destMode;
+            }
+        } else {
+            // These blend modes are not supported by OpenGL directly and have
+            // to be implemented using shaders. Since the shader will perform
+            // the blending, turn blending off here
+            if (mExtensions.hasFramebufferFetch()) {
+                description.framebufferMode = mode;
+            }
+
+            if (mCaches.blend) {
+                glDisable(GL_BLEND);
+            }
+            blend = false;
         }
     } else if (mCaches.blend) {
         glDisable(GL_BLEND);
@@ -983,10 +1003,14 @@
 
 void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
     if (paint) {
-        const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
-        if (!isMode) {
-            // Assume SRC_OVER
-            *mode = SkXfermode::kSrcOver_Mode;
+        if (!mExtensions.hasFramebufferFetch()) {
+            const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
+            if (!isMode) {
+                // Assume SRC_OVER
+                *mode = SkXfermode::kSrcOver_Mode;
+            }
+        } else {
+            *mode = getXfermode(paint->getXfermode());
         }
 
         // Skia draws using the color's alpha channel if < 255
@@ -1002,6 +1026,13 @@
     }
 }
 
+SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
+    if (mode == NULL) {
+        return SkXfermode::kSrcOver_Mode;
+    }
+    return mode->fMode;
+}
+
 void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
     glActiveTexture(gTextureUnits[textureUnit]);
     glBindTexture(GL_TEXTURE_2D, texture);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0e90d20..50f42c2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -322,7 +322,9 @@
      * Enable or disable blending as necessary. This function sets the appropriate
      * blend function based on the specified xfermode.
      */
-    inline void chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied = true);
+    inline void chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description);
+
+    inline SkXfermode::Mode getXfermode(SkXfermode* mode);
 
     /**
      * Use the specified program with the current GL context. If the program is already
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 39fe85a..ff65c1b 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -66,6 +66,8 @@
 // Fragment shaders snippets
 ///////////////////////////////////////////////////////////////////////////////
 
+const char* gFS_Header_Extension_FramebufferFetch =
+        "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
 const char* gFS_Header =
         "precision mediump float;\n\n";
 const char* gFS_Uniforms_Color =
@@ -115,6 +117,8 @@
         "    fragColor = bitmapColor * fragColor.a;\n";
 const char* gFS_Main_FragColor =
         "    gl_FragColor = fragColor;\n";
+const char* gFS_Main_FragColor_Blend =
+        "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
 const char* gFS_Main_ApplyColorOp[4] = {
         // None
         "",
@@ -281,7 +285,14 @@
 
 String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
     // Set the default precision
-    String8 shader(gFS_Header);
+    String8 shader;
+
+    bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
+    if (blendFramebuffer) {
+        shader.append(gFS_Header_Extension_FramebufferFetch);
+    }
+
+    shader.append(gFS_Header);
 
     // Varyings
     if (description.hasTexture) {
@@ -315,6 +326,9 @@
     if (description.colorOp == ProgramDescription::kColorBlend) {
         generateBlend(shader, "blendColors", description.colorMode);
     }
+    if (blendFramebuffer) {
+        generateBlend(shader, "blendFramebuffer", description.framebufferMode);
+    }
     if (description.isBitmapNpot) {
         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
     }
@@ -359,7 +373,11 @@
         // Apply the color op if needed
         shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
         // Output the fragment
-        shader.append(gFS_Main_FragColor);
+        if (!blendFramebuffer) {
+            shader.append(gFS_Main_FragColor);
+        } else {
+            shader.append(gFS_Main_FragColor_Blend);
+        }
     }
     // End the shader
     shader.append(gFS_Footer);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index f211ab6..8f5304d 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -35,7 +35,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 // Debug
-#define DEBUG_PROGRAM_CACHE 0
+#define DEBUG_PROGRAM_CACHE 1
 
 // Debug
 #if DEBUG_PROGRAM_CACHE
@@ -61,6 +61,7 @@
 #define PROGRAM_MAX_XFERMODE 0x1f
 #define PROGRAM_XFERMODE_SHADER_SHIFT 26
 #define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
+#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
 
 #define PROGRAM_BITMAP_WRAPS_SHIFT 9
 #define PROGRAM_BITMAP_WRAPT_SHIFT 11
@@ -93,7 +94,8 @@
         hasBitmap(false), isBitmapNpot(false), hasGradient(false),
         shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false),
         bitmapWrapS(GL_CLAMP_TO_EDGE), bitmapWrapT(GL_CLAMP_TO_EDGE),
-        colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode) {
+        colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode),
+        framebufferMode(SkXfermode::kClear_Mode) {
     }
 
     // Texturing
@@ -113,6 +115,10 @@
     int colorOp;
     SkXfermode::Mode colorMode;
 
+    // Framebuffer blending (requires Extensions.hasFramebufferFetch())
+    // Ignored for all values < SkXfermode::kPlus_Mode
+    SkXfermode::Mode framebufferMode;
+
     inline uint32_t getEnumForWrap(GLenum wrap) const {
         switch (wrap) {
             case GL_CLAMP_TO_EDGE:
@@ -156,6 +162,7 @@
             case kColorNone:
                 break;
         }
+        key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
         return key;
     }
 }; // struct ProgramDescription
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index e5ece8e..f6c55e4 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -65,6 +65,20 @@
 
 typedef void* (*android_pthread_entry)(void*);
 
+static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
+static bool gDoSchedulingGroup = true;
+
+static void checkDoSchedulingGroup(void) {
+    char buf[PROPERTY_VALUE_MAX];
+    int len = property_get("debug.sys.noschedgroups", buf, "");
+    if (len > 0) {
+        int temp;
+        if (sscanf(buf, "%d", &temp) == 1) {
+            gDoSchedulingGroup = temp == 0;
+        }
+    }
+}
+
 struct thread_data_t {
     thread_func_t   entryFunction;
     void*           userData;
@@ -80,6 +94,15 @@
         char * name = t->threadName;
         delete t;
         setpriority(PRIO_PROCESS, 0, prio);
+        pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+        if (gDoSchedulingGroup) {
+            if (prio >= ANDROID_PRIORITY_BACKGROUND) {
+                set_sched_policy(androidGetTid(), SP_BACKGROUND);
+            } else {
+                set_sched_policy(androidGetTid(), SP_FOREGROUND);
+            }
+        }
+        
         if (name) {
 #if defined(HAVE_PRCTL)
             // Mac OS doesn't have this, and we build libutil for the host too
@@ -281,22 +304,6 @@
 #endif
 }
 
-#if defined(HAVE_PTHREADS)
-static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
-static bool gDoSchedulingGroup = true;
-
-static void checkDoSchedulingGroup(void) {
-    char buf[PROPERTY_VALUE_MAX];
-    int len = property_get("debug.sys.noschedgroups", buf, "");
-    if (len > 0) {
-        int temp;
-        if (sscanf(buf, "%d", &temp) == 1) {
-            gDoSchedulingGroup = temp == 0;
-        }
-    }
-}
-#endif
-
 int androidSetThreadSchedulingGroup(pid_t tid, int grp)
 {
     if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 3487b0f..ad029a6 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -89,7 +89,7 @@
         mContext = context;
         mMediaProvider = context.getContentResolver().acquireProvider("media");
         mVolumeName = volumeName;
-        mObjectsUri = Files.getContentUri(volumeName);
+        mObjectsUri = Files.getMtpObjectsUri(volumeName);
         mMediaScanner = new MediaScanner(context);
         openDevicePropertiesDatabase(context);
     }
@@ -246,6 +246,8 @@
         return new int[] {
             // allow transfering arbitrary files
             MtpConstants.FORMAT_UNDEFINED,
+            MtpConstants.FORMAT_ASSOCIATION,
+            MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST,
         };
     }
 
@@ -479,7 +481,7 @@
     private int deleteFile(int handle) {
         Log.d(TAG, "deleteFile: " + handle);
         mDatabaseModified = true;
-        Uri uri = Files.getContentUri(mVolumeName, handle);
+        Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
         try {
             if (mMediaProvider.delete(uri, null, null) == 1) {
                 return MtpConstants.RESPONSE_OK;
@@ -494,7 +496,7 @@
 
     private int[] getObjectReferences(int handle) {
         Log.d(TAG, "getObjectReferences for: " + handle);
-        Uri uri = Files.getReferencesUri(mVolumeName, handle);
+        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
         Cursor c = null;
         try {
             c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null);
@@ -522,7 +524,7 @@
 
     private int setObjectReferences(int handle, int[] references) {
         mDatabaseModified = true;
-        Uri uri = Files.getReferencesUri(mVolumeName, handle);
+        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
         int count = references.length;
         ContentValues[] valuesList = new ContentValues[count];
         for (int i = 0; i < count; i++) {
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 24fe2db..82b4ac1 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -451,7 +451,7 @@
         return;
     }
     if (mr->initCheck() != NO_ERROR) {
-        jniThrowException(env, "java/lang/IOException", "Unable to initialize camera");
+        jniThrowException(env, "java/lang/RuntimeException", "Unable to initialize media recorder");
         return;
     }
 
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
index 495b38f..8339d3c 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
@@ -64,7 +64,7 @@
 #define LVDBE_PERSISTENT_COEF_ALIGN      4       /* 32-bit alignment for coef */
 #define LVDBE_SCRATCH_ALIGN              4       /* 32-bit alignment for long data */
 
-#define LVDBE_SCRATCHBUFFERS_INPLACE     4       /* Number of buffers required for inplace processing */
+#define LVDBE_SCRATCHBUFFERS_INPLACE     6       /* Number of buffers required for inplace processing */
 
 #define LVDBE_MIXER_TC                   5       /* Mixer time  */
 #define LVDBE_BYPASS_MIXER_TC            100     /* Bypass mixer time */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
index 9a40f68..ac2ef9d 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
@@ -496,7 +496,6 @@
      * Update the bypass mixer time constant
      */
     if((pPrivate->NewParams.SampleRate   != pPrivate->CurrentParams.SampleRate)   ||
-       (pPrivate->NewParams.SourceFormat != pPrivate->CurrentParams.SourceFormat) ||
        (pPrivate->bFirstControl          == LVM_TRUE))
     {
         LVM_UINT16   NumChannels = 1;                       /* Assume MONO format */
@@ -508,11 +507,7 @@
         pPrivate->FeedbackMixer[2].Alpha=Alpha;
         pPrivate->FeedbackMixer[3].Alpha=Alpha;
 
-        if (pPrivate->NewParams.SourceFormat != LVM_MONO)
-        {
-            /* Stereo or Mono-in-Stereo format data */
-            NumChannels = 2;
-        }
+        NumChannels = 2;                                    /* Always stereo output */
         pPrivate->BypassMixer.Alpha1 = (LVM_INT32)LVM_Mixer_TimeConstant(LVREV_BYPASSMIXER_TC, LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
         pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
         pPrivate->GainMixer.Alpha    = pPrivate->BypassMixer.Alpha1;
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
index 81521ba..5c7a8a0 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
@@ -54,7 +54,8 @@
    LVREV_Instance_st     *pLVREV_Private = (LVREV_Instance_st *)hInstance;
    LVM_INT32             *pInput  = (LVM_INT32 *)pInData;
    LVM_INT32             *pOutput = pOutData;
-   LVM_INT32             SamplesToProcess, RemainingSamples, format;
+   LVM_INT32             SamplesToProcess, RemainingSamples;
+   LVM_INT32             format = 1;
 
     /*
      * Check for error conditions
@@ -66,7 +67,6 @@
         return LVREV_NULLADDRESS;
     }
 
-
     /*
      * Apply the new controls settings if required
      */
@@ -95,9 +95,31 @@
         return LVREV_SUCCESS;
     }
 
+    /*
+     * If OFF copy and reformat the data as necessary
+     */
+    if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF)
+    {
+        if(pInput != pOutput)
+        {
+            /*
+             * Copy the data to the output buffer, convert to stereo is required
+             */
+
+            if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
+                MonoTo2I_32(pInput, pOutput, NumSamples);
+            } else {
+                Copy_16((LVM_INT16 *)pInput,
+                        (LVM_INT16 *)pOutput,
+                        (LVM_INT16)(NumSamples << 2)); // 32 bit data, stereo
+            }
+        }
+
+        return LVREV_SUCCESS;
+    }
+
     RemainingSamples = (LVM_INT32)NumSamples;
 
-    format = 1;
     if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO)
     {
         format = 2;
@@ -106,51 +128,24 @@
     while (RemainingSamples!=0)
     {
         /*
-         * If OFF copy and reformat the data as necessary
+         * Process the data
          */
-        if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF)
+
+        if(RemainingSamples >  pLVREV_Private->MaxBlkLen)
         {
-            if((pInput != pOutput) || (pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO))
-            {
-                /*
-                 * Copy the data to the output buffer
-                 */
-
-                if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO)
-                {
-                    RemainingSamples = (RemainingSamples << 1);           /* Stereo data */
-                }
-
-                Copy_16((LVM_INT16 *)pInput,
-                        (LVM_INT16 *)pOutput,
-                        (LVM_INT16)(RemainingSamples << 1));
-            }
-
+            SamplesToProcess =  pLVREV_Private->MaxBlkLen;
+            RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess);
+        }
+        else
+        {
+            SamplesToProcess = RemainingSamples;
             RemainingSamples = 0;
         }
 
-        /*
-         * Process the data
-         */
-        else
-        {
+        ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
 
-            if(RemainingSamples >  pLVREV_Private->MaxBlkLen)
-            {
-                SamplesToProcess =  pLVREV_Private->MaxBlkLen;
-                RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess);
-            }
-            else
-            {
-                SamplesToProcess = RemainingSamples;
-                RemainingSamples = 0;
-            }
-
-            ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
-
-            pInput  = (LVM_INT32 *)(pInput +(SamplesToProcess*format));
-            pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*format));
-        }
+        pInput  = (LVM_INT32 *)(pInput +(SamplesToProcess*format));
+        pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*2));      // Always stereo output
     }
 
     return LVREV_SUCCESS;
@@ -420,26 +415,13 @@
                             pPrivate->pScratchDelayLine[1],
                             (LVM_INT16)NumSamples);
 
-             if(pPrivate->CurrentParams.SourceFormat != LVM_MONO)
-             {
-                JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
-                               pPrivate->pScratchDelayLine[1],
-                               pTemp,
-                               (LVM_INT16)NumSamples);
 
-             }
-             else
-             {
-                 Add2_Sat_32x32(pPrivate->pScratchDelayLine[1],
-                                pPrivate->pScratchDelayLine[0],
-                                (LVM_INT16)NumSamples);
+            JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
+                           pPrivate->pScratchDelayLine[1],
+                           pTemp,
+                           (LVM_INT16)NumSamples);
 
-                /*Apply 3-dB gain in-order to compensate for the gain change in stereo mode*/
-                Mult3s_32x16(pPrivate->pScratchDelayLine[0],
-                             LVREV_MIN3DB,
-                             pTemp,
-                             (LVM_INT16)NumSamples);
-             }
+
             break;
         case LVREV_DELAYLINES_2:
 
@@ -447,49 +429,25 @@
                       (LVM_INT16*)pScratch,
                       (LVM_INT16)(NumSamples << 1));
 
-
-
-             if(pPrivate->CurrentParams.SourceFormat != LVM_MONO)
-             {
-
-                Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0],
-                                -0x8000,
-                                pScratch,
-                                (LVM_INT16)NumSamples);
-             }
+            Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0],
+                            -0x8000,
+                            pScratch,
+                            (LVM_INT16)NumSamples);
 
              Add2_Sat_32x32(pPrivate->pScratchDelayLine[1],
                             pPrivate->pScratchDelayLine[0],
                             (LVM_INT16)NumSamples);
 
 
-             if(pPrivate->CurrentParams.SourceFormat != LVM_MONO)
-             {
-                 JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
-                                pScratch,
-                                pTemp,
-                                (LVM_INT16)NumSamples);
-             }
-             else
-             {
-                Copy_16(    (LVM_INT16*)pPrivate->pScratchDelayLine[0],
-                            (LVM_INT16*)pTemp,
-                            (LVM_INT16)(NumSamples << 1));
-
-             }
-            break;
-        case LVREV_DELAYLINES_1:
-            if(pPrivate->CurrentParams.SourceFormat != LVM_MONO)
-            {
-
-                MonoTo2I_32(pPrivate->pScratchDelayLine[0],
+             JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
+                            pScratch,
                             pTemp,
                             (LVM_INT16)NumSamples);
-            }
-            else
-            {
-                pTemp = pPrivate->pScratchDelayLine[0];
-            }
+            break;
+        case LVREV_DELAYLINES_1:
+            MonoTo2I_32(pPrivate->pScratchDelayLine[0],
+                        pTemp,
+                        (LVM_INT16)NumSamples);
             break;
         default:
             break;
@@ -499,30 +457,15 @@
     /*
      *  Dry/wet mixer
      */
-    if(pPrivate->CurrentParams.SourceFormat != LVM_MONO)
-    {
-        size = (LVM_INT16)(NumSamples << 1);
-    }
-    else
-    {
-        size = (LVM_INT16)NumSamples;
-    }
 
+    size = (LVM_INT16)(NumSamples << 1);
     MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
-                           pInput,
+                           pTemp,
                            pTemp,
                            pOutput,
                            size);
 
     /* Apply Gain*/
-    if(pPrivate->CurrentParams.SourceFormat != LVM_MONO)
-    {
-        size = (LVM_INT16)(NumSamples << 1);
-    }
-    else
-    {
-        size = (LVM_INT16)NumSamples;
-    }
 
     Shift_Sat_v32xv32 (LVREV_OUTPUTGAIN_SHIFT,
                        pOutput,
@@ -533,6 +476,7 @@
                            pOutput,
                            pOutput,
                            size);
+
     return;
 }
 
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index b3e1531..60f4288 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -431,26 +431,15 @@
         pContext->InFrames32[i] = (LVM_INT32)pIn[i]<<8;
     }
 
-     // If the input was MONO, convert to STEREO
-    if(pContext->config.inputCfg.channels == CHANNEL_MONO){
-        //LOGV("\tConverting Output from MONO to STEREO");
-        MonoTo2I_32(pContext->InFrames32, pContext->InFrames32, frameCount);
-    }
-
-    //LOGV("\tProcess, frames: %d, InFormat: %d(MONO=%d), OutFormat: %d(STEREO=%d)",
-    //frameCount, pContext->config.inputCfg.channels, CHANNEL_MONO,
-    //pContext->config.outputCfg.channels, CHANNEL_STEREO);
-
     if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
         memset(pContext->OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2); //always stereo here
     } else {
         if(pContext->bEnabled == LVM_FALSE && pContext->SamplesToExitCount > 0) {
-            memset(pContext->InFrames32,
-                   0,
-                   frameCount * sizeof(LVM_INT32) * 2); //always stereo here
+            memset(pContext->InFrames32,0,frameCount * sizeof(LVM_INT32) * samplesPerFrame);
+            LOGV("\tZeroing %d samples per frame at the end of call", samplesPerFrame);
         }
 
-        /* Process the samples */
+        /* Process the samples, producing a stereo output */
         LvmStatus = LVREV_Process(pContext->hInstance,      /* Instance handle */
                                   pContext->InFrames32,     /* Input buffer */
                                   pContext->OutFrames32,    /* Output buffer */
@@ -677,7 +666,7 @@
 
     /* Set the capabilities */
     InstParams.MaxBlockSize  = MAX_CALL_SIZE;
-    InstParams.SourceFormat  = LVM_STEREO;
+    InstParams.SourceFormat  = LVM_STEREO;          // Max format, could be mono during process
     InstParams.NumDelays     = LVREV_DELAYLINES_4;
 
     /* Allocate memory, forcing alignment */
@@ -742,7 +731,12 @@
     /* General parameters */
     params.OperatingMode  = LVM_MODE_ON;
     params.SampleRate     = LVM_FS_44100;
-    params.SourceFormat   = LVM_STEREO;
+
+    if(pContext->config.inputCfg.channels == CHANNEL_MONO){
+        params.SourceFormat   = LVM_MONO;
+    } else {
+        params.SourceFormat   = LVM_STEREO;
+    }
 
     /* Reverb parameters */
     params.Level          = 0;
@@ -1790,8 +1784,9 @@
     if (pContext->bEnabled == LVM_FALSE){
         if( pContext->SamplesToExitCount > 0){
             pContext->SamplesToExitCount -= outBuffer->frameCount;
+            LOGV("\tReverb_process() Effect is being stopped %d", pContext->SamplesToExitCount);
         }else{
-            LOGV("\tReverb_process() ERROR Effect is not enabled %d", pContext->SamplesToExitCount);
+            LOGV("\tReverb_process() Effect is being stopped");
             return -ENODATA;
         }
     }
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 2e36968..82c0426 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -459,7 +459,8 @@
 
 MP3Extractor::MP3Extractor(
         const sp<DataSource> &source, const sp<AMessage> &meta)
-    : mDataSource(source),
+    : mInitCheck(NO_INIT),
+      mDataSource(source),
       mFirstFramePos(-1),
       mFixedHeader(0),
       mByteNumber(0) {
@@ -480,53 +481,54 @@
         success = true;
     } else {
         success = Resync(mDataSource, 0, &pos, &header);
-        CHECK(success);
     }
 
-    if (success) {
-        mFirstFramePos = pos;
-        mFixedHeader = header;
+    if (!success) {
+        // mInitCheck will remain NO_INIT
+        return;
+    }
 
-        size_t frame_size;
-        int sample_rate;
-        int num_channels;
-        int bitrate;
-        get_mp3_frame_size(
-                header, &frame_size, &sample_rate, &num_channels, &bitrate);
+    mFirstFramePos = pos;
+    mFixedHeader = header;
 
-        mMeta = new MetaData;
+    size_t frame_size;
+    int sample_rate;
+    int num_channels;
+    int bitrate;
+    get_mp3_frame_size(
+            header, &frame_size, &sample_rate, &num_channels, &bitrate);
 
-        mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
-        mMeta->setInt32(kKeySampleRate, sample_rate);
-        mMeta->setInt32(kKeyBitRate, bitrate * 1000);
-        mMeta->setInt32(kKeyChannelCount, num_channels);
+    mMeta = new MetaData;
 
-        int64_t duration;
-        parse_xing_header(
-                mDataSource, mFirstFramePos, NULL, &mByteNumber,
-                mTableOfContents, NULL, &duration);
-        if (duration > 0) {
-            mMeta->setInt64(kKeyDuration, duration);
-        } else {
-            off_t fileSize;
-            if (mDataSource->getSize(&fileSize) == OK) {
-                mMeta->setInt64(
-                        kKeyDuration,
-                        8000LL * (fileSize - mFirstFramePos) / bitrate);
-            }
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+    mMeta->setInt32(kKeySampleRate, sample_rate);
+    mMeta->setInt32(kKeyBitRate, bitrate * 1000);
+    mMeta->setInt32(kKeyChannelCount, num_channels);
+
+    int64_t duration;
+    parse_xing_header(
+            mDataSource, mFirstFramePos, NULL, &mByteNumber,
+            mTableOfContents, NULL, &duration);
+    if (duration > 0) {
+        mMeta->setInt64(kKeyDuration, duration);
+    } else {
+        off_t fileSize;
+        if (mDataSource->getSize(&fileSize) == OK) {
+            mMeta->setInt64(
+                    kKeyDuration,
+                    8000LL * (fileSize - mFirstFramePos) / bitrate);
         }
     }
-}
 
-MP3Extractor::~MP3Extractor() {
+    mInitCheck = OK;
 }
 
 size_t MP3Extractor::countTracks() {
-    return (mFirstFramePos < 0) ? 0 : 1;
+    return mInitCheck != OK ? 0 : 1;
 }
 
 sp<MediaSource> MP3Extractor::getTrack(size_t index) {
-    if (mFirstFramePos < 0 || index != 0) {
+    if (mInitCheck != OK || index != 0) {
         return NULL;
     }
 
@@ -536,7 +538,7 @@
 }
 
 sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
-    if (mFirstFramePos < 0 || index != 0) {
+    if (mInitCheck != OK || index != 0) {
         return NULL;
     }
 
@@ -713,7 +715,7 @@
 sp<MetaData> MP3Extractor::getMetaData() {
     sp<MetaData> meta = new MetaData;
 
-    if (mFirstFramePos < 0) {
+    if (mInitCheck != OK) {
         return meta;
     }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index ba90407..4bbc251 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -872,7 +872,11 @@
             }
 
             size_t max_size;
-            CHECK_EQ(mLastTrack->sampleTable->getMaxSampleSize(&max_size), OK);
+            err = mLastTrack->sampleTable->getMaxSampleSize(&max_size);
+
+            if (err != OK) {
+                return err;
+            }
 
             // Assume that a given buffer only contains at most 10 fragments,
             // each fragment originally prefixed with a 2 byte length will
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 806836d..de4233d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -346,9 +346,10 @@
         // If file size is set to be larger than the 32 bit file
         // size limit, treat it as an error.
         if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
-            LOGE("32-bit file size limit too big: %lld bytes",
-                mMaxFileSizeLimitBytes);
-            return UNKNOWN_ERROR;
+            LOGW("32-bi file size limit (%lld bytes) too big. "
+                 "It is changed to %lld bytes",
+                mMaxFileSizeLimitBytes, kMax32BitFileSize);
+            mMaxFileSizeLimitBytes = kMax32BitFileSize;
         }
     }
 
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 0dacb53..5a453e9 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -26,6 +26,8 @@
 
 #include "include/TimedEventQueue.h"
 
+#include <cutils/sched_policy.h>
+
 #include <sys/prctl.h>
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -209,6 +211,8 @@
 #endif
 
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
+    set_sched_policy(androidGetTid(), SP_FOREGROUND);
+
     static_cast<TimedEventQueue *>(me)->threadEntry();
 
 #ifdef ANDROID_SIMULATOR
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 0e6ccde..30136e7d 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -37,10 +37,9 @@
 
     virtual sp<MetaData> getMetaData();
 
-protected:
-    virtual ~MP3Extractor();
-
 private:
+    status_t mInitCheck;
+
     sp<DataSource> mDataSource;
     off_t mFirstFramePos;
     sp<MetaData> mMeta;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 9228b0b..bd5fad2 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -240,7 +240,7 @@
         memset(images, 0, sizeof(images));
     }
     EGLDisplay dpy;
-    EGLConfig context;
+    EGLContext context;
     EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
 };
 
@@ -1770,7 +1770,7 @@
          egl_connection_t* const cnx = &gEGLImpl[i];
          if (image->images[i] != EGL_NO_IMAGE_KHR) {
              if (cnx->dso) {
-                 if (cnx->egl.eglCreateImageKHR) {
+                 if (cnx->egl.eglDestroyImageKHR) {
                      if (cnx->egl.eglDestroyImageKHR(
                              dp->disp[i].dpy, image->images[i])) {
                          success = true;
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
index 9f80ed4..4d10ee5 100644
--- a/opengl/tests/angeles/app-linux.cpp
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -63,7 +63,7 @@
 int gAppAlive = 1;
 
 static const char sAppName[] =
-    "San Angeles Observation OpenGL ES version example (Linux)";
+        "San Angeles Observation OpenGL ES version example (Linux)";
 
 static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
 static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
@@ -74,22 +74,22 @@
 const char *egl_strerror(unsigned err)
 {
     switch(err){
-    case EGL_SUCCESS: return "SUCCESS";
-    case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
-    case EGL_BAD_ACCESS: return "BAD ACCESS";
-    case EGL_BAD_ALLOC: return "BAD ALLOC";
-    case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
-    case EGL_BAD_CONFIG: return "BAD CONFIG";
-    case EGL_BAD_CONTEXT: return "BAD CONTEXT";
-    case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
-    case EGL_BAD_DISPLAY: return "BAD DISPLAY";
-    case EGL_BAD_MATCH: return "BAD MATCH";
-    case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
-    case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
-    case EGL_BAD_PARAMETER: return "BAD PARAMETER";
-    case EGL_BAD_SURFACE: return "BAD_SURFACE";
-//    case EGL_CONTEXT_LOST: return "CONTEXT LOST";
-    default: return "UNKNOWN";
+        case EGL_SUCCESS: return "SUCCESS";
+        case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
+        case EGL_BAD_ACCESS: return "BAD ACCESS";
+        case EGL_BAD_ALLOC: return "BAD ALLOC";
+        case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
+        case EGL_BAD_CONFIG: return "BAD CONFIG";
+        case EGL_BAD_CONTEXT: return "BAD CONTEXT";
+        case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
+        case EGL_BAD_DISPLAY: return "BAD DISPLAY";
+        case EGL_BAD_MATCH: return "BAD MATCH";
+        case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
+        case EGL_BAD_PARAMETER: return "BAD PARAMETER";
+        case EGL_BAD_SURFACE: return "BAD_SURFACE";
+        //    case EGL_CONTEXT_LOST: return "CONTEXT LOST";
+        default: return "UNKNOWN";
     }
 }
 
@@ -118,52 +118,59 @@
         fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
 }
 
-static int initGraphics()
+static int initGraphics(unsigned samples)
 {
     EGLint configAttribs[] = {
-         EGL_DEPTH_SIZE, 16,
-         EGL_NONE
-     };
-     
-     EGLint majorVersion;
-     EGLint minorVersion;
-     EGLContext context;
-     EGLConfig config;
-     EGLSurface surface;
-     EGLint w, h;
-     EGLDisplay dpy;
+            EGL_DEPTH_SIZE, 16,
+            EGL_SAMPLE_BUFFERS, samples ? 1 : 0,
+                    EGL_SAMPLES, samples,
+                    EGL_NONE
+    };
 
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
-     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-     eglInitialize(dpy, &majorVersion, &minorVersion);
-          
-     status_t err = EGLUtils::selectConfigForNativeWindow(
-             dpy, configAttribs, window, &config);
-     if (err) {
-         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
-         return 0;
-     }
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLConfig config;
+    EGLSurface surface;
+    EGLint w, h;
+    EGLDisplay dpy;
 
-     surface = eglCreateWindowSurface(dpy, config, window, NULL);
-     egl_error("eglCreateWindowSurface");
+    EGLNativeWindowType window = android_createDisplaySurface();
 
-     fprintf(stderr,"surface = %p\n", surface);
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglInitialize(dpy, &majorVersion, &minorVersion);
 
-     context = eglCreateContext(dpy, config, NULL, NULL);
-     egl_error("eglCreateContext");
-     fprintf(stderr,"context = %p\n", context);
-     
-     eglMakeCurrent(dpy, surface, surface, context);   
-     egl_error("eglMakeCurrent");
+    status_t err = EGLUtils::selectConfigForNativeWindow(
+            dpy, configAttribs, window, &config);
+    if (err) {
+        fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+        return 0;
+    }
 
-     eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
-     eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
+    surface = eglCreateWindowSurface(dpy, config, window, NULL);
+    egl_error("eglCreateWindowSurface");
+
+    fprintf(stderr,"surface = %p\n", surface);
+
+    context = eglCreateContext(dpy, config, NULL, NULL);
+    egl_error("eglCreateContext");
+    fprintf(stderr,"context = %p\n", context);
+
+    eglMakeCurrent(dpy, surface, surface, context);
+    egl_error("eglMakeCurrent");
+
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
 
     sEglDisplay = dpy;
     sEglSurface = surface;
     sEglContext = context;
 
+    if (samples == 0) {
+        // GL_MULTISAMPLE is enabled by default
+        glDisable(GL_MULTISAMPLE);
+    }
+
     return EGL_TRUE;
 }
 
@@ -179,11 +186,14 @@
 
 int main(int argc, char *argv[])
 {
-    // not referenced:
-    argc = argc;
-    argv = argv;
+    unsigned samples = 0;
+    printf("usage: %s [samples]\n", argv[0]);
+    if (argc == 2) {
+        samples = atoi( argv[1] );
+        printf("Multisample enabled: GL_SAMPLES = %u\n", samples);
+    }
 
-    if (!initGraphics())
+    if (!initGraphics(samples))
     {
         fprintf(stderr, "Graphics initialization failed.\n");
         return EXIT_FAILURE;
@@ -195,7 +205,7 @@
     int frameCount = 0;
     gettimeofday(&timeTemp, NULL);
     double totalTime = timeTemp.tv_usec/1000000.0 + timeTemp.tv_sec;
-    
+
     while (gAppAlive)
     {
         struct timeval timeNow;
diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp
index 36db1b0..a069f67 100644
--- a/opengl/tests/gl_perf/fill_common.cpp
+++ b/opengl/tests/gl_perf/fill_common.cpp
@@ -14,9 +14,15 @@
  * limitations under the License.
  */
 
+#include "fragment_shaders.cpp"
+
 FILE * fOut = NULL;
 void ptSwap();
 
+static char gCurrentTestName[1024];
+static uint32_t gWidth = 0;
+static uint32_t gHeight = 0;
+
 static void checkGlError(const char* op) {
     for (GLint error = glGetError(); error; error
             = glGetError()) {
@@ -112,20 +118,21 @@
     gTime = getTime();
 }
 
-void endTimer(const char *str, int w, int h, double dc, int count) {
+
+static void endTimer(int count) {
     uint64_t t2 = getTime();
     double delta = ((double)(t2 - gTime)) / 1000000000;
-    double pixels = dc * (w * h) * count;
+    double pixels = (gWidth * gHeight) * count;
     double mpps = pixels / delta / 1000000;
-    double dc60 = pixels / delta / (w * h) / 60;
+    double dc60 = ((double)count) / delta / 60;
 
     if (fOut) {
-        fprintf(fOut, "%s, %f, %f\r\n", str, mpps, dc60);
+        fprintf(fOut, "%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
         fflush(fOut);
     } else {
-        printf("%s, %f, %f\n", str, mpps, dc60);
+        printf("%s, %f, %f\n", gCurrentTestName, mpps, dc60);
     }
-    LOGI("%s, %f, %f\r\n", str, mpps, dc60);
+    LOGI("%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
 }
 
 
@@ -137,86 +144,17 @@
     "varying vec4 v_color;\n"
     "varying vec2 v_tex0;\n"
     "varying vec2 v_tex1;\n"
+    "uniform vec2 u_texOff;\n"
 
     "void main() {\n"
     "    v_color = a_color;\n"
     "    v_tex0 = a_tex0;\n"
     "    v_tex1 = a_tex1;\n"
+    "    v_tex0.x += u_texOff.x;\n"
+    "    v_tex1.y += u_texOff.y;\n"
     "    gl_Position = a_pos;\n"
     "}\n";
 
-static const char gShaderPrefix[] =
-    "precision mediump float;\n"
-    "uniform vec4 u_color;\n"
-    "uniform vec4 u_0;\n"
-    "uniform vec4 u_1;\n"
-    "uniform vec4 u_2;\n"
-    "uniform vec4 u_3;\n"
-    "varying vec4 v_color;\n"
-    "varying vec2 v_tex0;\n"
-    "varying vec2 v_tex1;\n"
-    "uniform sampler2D u_tex0;\n"
-    "uniform sampler2D u_tex1;\n"
-    "void main() {\n";
-
-static const char gShaderPostfix[] =
-    "  gl_FragColor = c;\n"
-    "}\n";
-
-
-static char * append(char *d, const char *s) {
-    size_t len = strlen(s);
-    memcpy(d, s, len);
-    return d + len;
-}
-
-static char * genShader(
-    bool useVarColor,
-    int texCount,
-    bool modulateFirstTex,
-    int extraMath)
-{
-    char *str = (char *)calloc(16 * 1024, 1);
-    char *tmp = append(str, gShaderPrefix);
-
-    if (modulateFirstTex || !texCount) {
-        if (useVarColor) {
-            tmp = append(tmp, "  vec4 c = v_color;\n");
-        } else {
-            tmp = append(tmp, "  vec4 c = u_color;\n");
-        }
-    } else {
-        tmp = append(tmp, "  vec4 c = texture2D(u_tex0, v_tex0);\n");
-    }
-
-    if (modulateFirstTex && texCount) {
-        tmp = append(tmp, "  c *= texture2D(u_tex0, v_tex0);\n");
-    }
-    if (texCount > 1) {
-        tmp = append(tmp, "  c *= texture2D(u_tex1, v_tex1);\n");
-    }
-
-    if (extraMath > 0) {
-        tmp = append(tmp, "  c *= u_0;\n");
-    }
-    if (extraMath > 1) {
-        tmp = append(tmp, "  c += u_1;\n");
-    }
-    if (extraMath > 2) {
-        tmp = append(tmp, "  c *= u_2;\n");
-    }
-    if (extraMath > 3) {
-        tmp = append(tmp, "  c += u_3;\n");
-    }
-
-
-    tmp = append(tmp, gShaderPostfix);
-    tmp[0] = 0;
-
-    //printf("%s", str);
-    return str;
-}
-
 static void setupVA() {
     static const float vtx[] = {
         -1.0f,-1.0f,
@@ -231,8 +169,8 @@
     static const float tex0[] = {
         0.0f,0.0f,
         1.0f,0.0f,
-        1.0f,1.0f,
-        0.0f,1.0f };
+        0.0f,1.0f,
+        1.0f,1.0f };
     static const float tex1[] = {
         1.0f,0.0f,
         1.0f,1.0f,
@@ -261,8 +199,8 @@
     }
 }
 
-static void doLoop(bool clear, int pgm, uint32_t w, uint32_t h, const char *str) {
-    if (clear) {
+static void doLoop(bool warmup, int pgm, uint32_t passCount) {
+    if (warmup) {
         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
         ptSwap();
@@ -272,7 +210,10 @@
 
     startTimer();
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-    for (int ct=0; ct < 100; ct++) {
+    for (uint32_t ct=0; ct < passCount; ct++) {
+        int loc = glGetUniformLocation(pgm, "u_texOff");
+        glUniform2f(loc, ((float)ct) / passCount, ((float)ct) / 2.f / passCount);
+
         randUniform(pgm, "u_color");
         randUniform(pgm, "u_0");
         randUniform(pgm, "u_1");
@@ -282,14 +223,24 @@
     }
     ptSwap();
     glFinish();
-    endTimer(str, w, h, 1, 100);
+    endTimer(passCount);
+}
+
+
+static uint32_t rgb(uint32_t r, uint32_t g, uint32_t b)
+{
+    uint32_t ret = 0xff000000;
+    ret |= r & 0xff;
+    ret |= (g & 0xff) << 8;
+    ret |= (b & 0xff) << 16;
+    return ret;
 }
 
 void genTextures() {
     uint32_t *m = (uint32_t *)malloc(1024*1024*4);
     for (int y=0; y < 1024; y++){
         for (int x=0; x < 1024; x++){
-            m[y*1024 + x] = 0xff0000ff | ((x & 0xff) << 8) | (y << 16);
+            m[y*1024 + x] = rgb(x, (((x+y) & 0xff) == 0x7f) * 0xff, y);
         }
     }
     glBindTexture(GL_TEXTURE_2D, 1);
@@ -301,7 +252,7 @@
 
     for (int y=0; y < 16; y++){
         for (int x=0; x < 16; x++){
-            m[y*16 + x] = 0xff0000ff | (x<<12) | (y<<20);
+            m[y*16 + x] = rgb(x << 4, (((x+y) & 0xf) == 0x7) * 0xff, y << 4);
         }
     }
     glBindTexture(GL_TEXTURE_2D, 2);
@@ -310,7 +261,38 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
+    free(m);
 }
 
+static void doSingleTest(uint32_t pgmNum, int tex) {
+    const char *pgmTxt = gFragmentTests[pgmNum]->txt;
+    int pgm = createProgram(gVertexShader, pgmTxt);
+    if (!pgm) {
+        printf("error running test\n");
+        return;
+    }
+    int loc = glGetUniformLocation(pgm, "u_tex0");
+    if (loc >= 0) glUniform1i(loc, 0);
+    loc = glGetUniformLocation(pgm, "u_tex1");
+    if (loc >= 0) glUniform1i(loc, 1);
+
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, tex);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, tex);
+    glActiveTexture(GL_TEXTURE0);
+
+    glBlendFunc(GL_ONE, GL_ONE);
+    glDisable(GL_BLEND);
+    //sprintf(str2, "%i, %i, %i, %i, %i, 0",
+            //useVarColor, texCount, modulateFirstTex, extraMath, tex0);
+    //doLoop(true, pgm, w, h, str2);
+    //doLoop(false, pgm, w, h, str2);
+
+    glEnable(GL_BLEND);
+    sprintf(gCurrentTestName, "%s, %i, %i, 1", gFragmentTests[pgmNum]->name, pgmNum, tex);
+    doLoop(true, pgm, 100);
+    doLoop(false, pgm, 100);
+}
 
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
index 0dd4e22..3f8faca 100644
--- a/opengl/tests/gl_perf/filltest.cpp
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -33,65 +33,19 @@
 
 #include "fill_common.cpp"
 
-static void doSingleTest(uint32_t w, uint32_t h,
-                         bool useVarColor,
-                         int texCount,
-                         bool modulateFirstTex,
-                         int extraMath,
-                         int tex0, int tex1) {
-    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
-    int pgm = createProgram(gVertexShader, pgmTxt);
-    if (!pgm) {
-        printf("error running test\n");
-        return;
-    }
-    int loc = glGetUniformLocation(pgm, "u_tex0");
-    if (loc >= 0) glUniform1i(loc, 0);
-    loc = glGetUniformLocation(pgm, "u_tex1");
-    if (loc >= 0) glUniform1i(loc, 1);
-
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, tex0);
-    glActiveTexture(GL_TEXTURE1);
-    glBindTexture(GL_TEXTURE_2D, tex1);
-    glActiveTexture(GL_TEXTURE0);
-
-    char str2[1024];
-
-    glBlendFunc(GL_ONE, GL_ONE);
-    glDisable(GL_BLEND);
-    //sprintf(str2, "%i, %i, %i, %i, %i, 0",
-            //useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-    //doLoop(true, pgm, w, h, str2);
-    //doLoop(false, pgm, w, h, str2);
-
-    glEnable(GL_BLEND);
-    sprintf(str2, "%i, %i, %i, %i, %i, 1",
-            useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-    doLoop(true, pgm, w, h, str2);
-    doLoop(false, pgm, w, h, str2);
-}
 
 bool doTest(uint32_t w, uint32_t h) {
+    gWidth = w;
+    gHeight = h;
     setupVA();
     genTextures();
 
     printf("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
 
-    for (int texCount = 0; texCount < 2; texCount++) {
-        for (int extraMath = 0; extraMath < 5; extraMath++) {
-
-            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
-            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
-            if (texCount) {
-                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
-                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
-
-                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
-                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
-                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
-                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
-            }
+    for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+        doSingleTest(num, 2);
+        if (gFragmentTests[num]->texCount) {
+            doSingleTest(num, 1);
         }
     }
 
diff --git a/opengl/tests/gl_perf/fragment_shaders.cpp b/opengl/tests/gl_perf/fragment_shaders.cpp
new file mode 100644
index 0000000..79d5ead
--- /dev/null
+++ b/opengl/tests/gl_perf/fragment_shaders.cpp
@@ -0,0 +1,139 @@
+
+typedef struct FragmentTestRec {
+	const char * name;
+	uint32_t texCount;
+	const char * txt;
+} FragmentTest;
+
+static FragmentTest fpFill = {
+	"Solid color", 0,
+
+    "precision mediump float;\n"
+    "uniform vec4 u_color;\n"
+    "void main() {\n"
+    "  gl_FragColor = u_color;\n"
+    "}\n"
+};
+
+static FragmentTest fpGradient = {
+	"Solid gradient", 0,
+
+    "precision mediump float;\n"
+    "varying lowp vec4 v_color;\n"
+    "void main() {\n"
+    "  gl_FragColor = v_color;\n"
+    "}\n"
+};
+
+static FragmentTest fpCopyTex = {
+	"Texture copy", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  gl_FragColor = texture2D(u_tex0, v_tex0);\n"
+    "}\n"
+};
+
+static FragmentTest fpCopyTexGamma = {
+	"Texture copy with gamma", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  vec4 t = texture2D(u_tex0, v_tex0);\n"
+    "  t.rgb = pow(t.rgb, vec3(1.4, 1.4, 1.4));\n"
+    "  gl_FragColor = t;\n"
+    "}\n"
+};
+
+static FragmentTest fpTexSpec = {
+	"Texture spec", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  vec4 t = texture2D(u_tex0, v_tex0);\n"
+    "  float simSpec = dot(gl_FragCoord.xyz, gl_FragCoord.xyz);\n"
+    "  simSpec = pow(clamp(simSpec, 0.1, 1.0), 40.0);\n"
+    "  gl_FragColor = t + vec4(simSpec, simSpec, simSpec, simSpec);\n"
+    "}\n"
+};
+
+static FragmentTest fpDepTex = {
+	"Dependent Lookup", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  vec4 t = texture2D(u_tex0, v_tex0);\n"
+    "  t += texture2D(u_tex0, t.xy);\n"
+    "  gl_FragColor = t;\n"
+    "}\n"
+};
+
+static FragmentTest fpModulateConstantTex = {
+	"Texture modulate constant", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "uniform vec4 u_color;\n"
+
+    "void main() {\n"
+    "  lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+	"  c *= u_color;\n"
+    "  gl_FragColor = c;\n"
+    "}\n"
+};
+
+static FragmentTest fpModulateVaryingTex = {
+	"Texture modulate gradient", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "varying lowp vec4 v_color;\n"
+    "uniform sampler2D u_tex0;\n"
+
+    "void main() {\n"
+    "  lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+	"  c *= v_color;\n"
+    "  gl_FragColor = c;\n"
+    "}\n"
+};
+
+static FragmentTest fpModulateVaryingConstantTex = {
+	"Texture modulate gradient constant", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "varying lowp vec4 v_color;\n"
+    "uniform sampler2D u_tex0;\n"
+    "uniform vec4 u_color;\n"
+
+    "void main() {\n"
+    "  lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+	"  c *= v_color;\n"
+	"  c *= u_color;\n"
+    "  gl_FragColor = c;\n"
+    "}\n"
+};
+
+static FragmentTest *gFragmentTests[] = {
+	&fpFill,
+	&fpGradient,
+	&fpCopyTex,
+	&fpCopyTexGamma,
+   &fpTexSpec,
+   &fpDepTex,
+	&fpModulateConstantTex,
+	&fpModulateVaryingTex,
+	&fpModulateVaryingConstantTex,
+
+};
+
+static const size_t gFragmentTestCount = sizeof(gFragmentTests) / sizeof(gFragmentTests[0]);
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
index e643292..f993371 100644
--- a/opengl/tests/gl_perfapp/jni/gl_code.cpp
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -32,82 +32,17 @@
 
 // Saves the parameters of the test (so we can print them out when we finish the timing.)
 
-char saveBuf[1024];
-
 
 int pgm;
 
 void ptSwap() {
 }
 
-static void doSingleTest(uint32_t w, uint32_t h,
-                         bool useVarColor,
-                         int texCount,
-                         bool modulateFirstTex,
-                         int extraMath,
-                         int tex0, int tex1) {
-    int doSingleTestState = (stateClock / doLoopStates) % doSingleTestStates;
-    // LOGI("doSingleTest %d\n", doSingleTestState);
-    switch (doSingleTestState) {
-	case 0: {
-	    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
-	    pgm = createProgram(gVertexShader, pgmTxt);
-	    if (!pgm) {
-		LOGE("error running test\n");
-		return;
-	    }
-	    int loc = glGetUniformLocation(pgm, "u_tex0");
-	    if (loc >= 0) glUniform1i(loc, 0);
-	    loc = glGetUniformLocation(pgm, "u_tex1");
-	    if (loc >= 0) glUniform1i(loc, 1);
+void doTest() {
+    uint32_t testNum = stateClock >> 2;
+    int texSize = ((stateClock >> 1) & 0x1) + 1;
 
-	    glActiveTexture(GL_TEXTURE0);
-	    glBindTexture(GL_TEXTURE_2D, tex0);
-	    glActiveTexture(GL_TEXTURE1);
-	    glBindTexture(GL_TEXTURE_2D, tex1);
-	    glActiveTexture(GL_TEXTURE0);
-
-
-	    glBlendFunc(GL_ONE, GL_ONE);
-	    glDisable(GL_BLEND);
-            char str2[1024];
-	    sprintf(str2, "%i, %i, %i, %i, %i, 0",
-		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-
-    	    doLoop((stateClock % doLoopStates) != 0, pgm, w, h, str2);
-	 }
-         break;
-         case 1: {
-            char str2[1024];
-	    glEnable(GL_BLEND);
-	    sprintf(str2, "%i, %i, %i, %i, %i, 1",
-		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-	    doLoop((stateClock % doLoopStates) != 0, pgm, w, h, str2);
-        }
-        break;
-    }
-}
-
-
-void doTest(uint32_t w, uint32_t h) {
-    int testState = stateClock / (doLoopStates * doSingleTestStates);
-    int texCount;
-    int extraMath;
-    int testSubState;
-    const int extraMathCount = 5;
-    const int texCount0SubTestCount = 2;
-    const int texCountNSubTestCount = 8;
-
-    if ( testState < extraMathCount * texCount0SubTestCount) {
-       texCount = 0; // Only 10 tests for texCount 0
-       extraMath = (testState / texCount0SubTestCount) % extraMathCount;
-       testSubState = testState % texCount0SubTestCount;
-    } else {
-       texCount = 1 + (testState - extraMathCount * texCount0SubTestCount) / (extraMathCount * texCountNSubTestCount);
-       extraMath = (testState / texCountNSubTestCount) % extraMathCount;
-       testSubState = testState % texCountNSubTestCount;
-    }
-    if (texCount >= 3) {
+    if (testNum >= gFragmentTestCount) {
        LOGI("done\n");
        if (fOut) {
            fclose(fOut);
@@ -117,36 +52,10 @@
        return;
     }
 
-
     // LOGI("doTest %d %d %d\n", texCount, extraMath, testSubState);
 
-    switch(testSubState) {
-	case 0:
-            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
-	break;
-	case 1:
-            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
-	break;
-	case 2:
-                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
-	break;
-	case 3:
-                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
-	break;
-
-	case 4:
-                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
-	break;
-	case 5:
-                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
-	break;
-	case 6:
-                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
-	break;
-	case 7:
-                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
-	break;
-    }
+//        for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+    doSingleTest(testNum, texSize);
 }
 
 extern "C" {
@@ -156,27 +65,27 @@
 
 JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height)
 {
+    gWidth = width;
+    gHeight = height;
     if (!done) {
-	    w = width;
-	    h = height;
-	    stateClock = 0;
-	    done = false;
-	    setupVA();
-	    genTextures();
-	    const char* fileName = "/sdcard/glperf.csv";
+            stateClock = 0;
+            done = false;
+            setupVA();
+            genTextures();
+            const char* fileName = "/sdcard/glperf.csv";
             if (fOut != NULL) {
                  LOGI("Closing partially written output.n");
                  fclose(fOut);
                  fOut = NULL;
             }
-	    LOGI("Writing to: %s\n",fileName);
-	    fOut = fopen(fileName, "w");
-	    if (fOut == NULL) {
-		LOGE("Could not open: %s\n", fileName);
-	    }
+            LOGI("Writing to: %s\n",fileName);
+            fOut = fopen(fileName, "w");
+            if (fOut == NULL) {
+                LOGE("Could not open: %s\n", fileName);
+            }
 
-	    LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
-	    if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
+            LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+            if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
     }
 }
 
@@ -184,11 +93,11 @@
 {
     if (! done) {
         if (stateClock > 0 && ((stateClock & 1) == 0)) {
-	    endTimer(saveBuf, w, h, 1, 100);
+            //endTimer(100);
         }
-        doTest(w, h);
+        doTest();
         stateClock++;
     } else {
-	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+            glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     }
 }
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
index 12d4ac4..bdc8c27 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
index 4f1f377..d0d1345 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
index c65f56a..4211b8c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
index 4aca0c7..d5ece7a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
index 24e07ab..6687b40 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
new file mode 100755
index 0000000..ba24082
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
new file mode 100755
index 0000000..5af2b05
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
new file mode 100755
index 0000000..9909b09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
new file mode 100755
index 0000000..0e02b8d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
new file mode 100755
index 0000000..f84ad32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png
new file mode 100755
index 0000000..d80a8ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png
new file mode 100755
index 0000000..31c976a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
new file mode 100755
index 0000000..c299e12
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png
new file mode 100755
index 0000000..a487f29
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png
new file mode 100755
index 0000000..816085b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png
new file mode 100755
index 0000000..0132019
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png
new file mode 100755
index 0000000..3903545
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png
new file mode 100755
index 0000000..ed099ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png
new file mode 100755
index 0000000..c930e4c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png
new file mode 100755
index 0000000..407a06c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png
new file mode 100755
index 0000000..6141f72
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png
new file mode 100755
index 0000000..d44a4cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png
new file mode 100755
index 0000000..54ebd9b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png
new file mode 100755
index 0000000..2fe0bbf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png
new file mode 100755
index 0000000..e58e019
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
index 511e22a..00a29a4 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
index 64f8087..11ee0f2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
index 90aaf71..fc135fc 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
index c21387e..3d33a62 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
index f2f6daa..f36e1eb 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
index 19ea80c..ef5dbf4 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
index ebfa6fb..dba9675 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
index 7ccd7de..2e5d82e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
index c614d0d..0985a09 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
index 5d6ef05..7a32c43 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
index adf5f95..b622556 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
index 9936f2a..04ec59e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
index 904c565..a47b982 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
index 1261c15..9d90e71 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
index 5e3122d6..920f290 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
index 55a2ad8..98e874a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
index d16b3e8..aea18ed 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
new file mode 100755
index 0000000..1a25a2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
index 2511083..77e6ee4 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
new file mode 100755
index 0000000..00d86bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
index e0799a5..c2574e1 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
new file mode 100755
index 0000000..70c030b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
index 2385c3a..55caecf 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
new file mode 100755
index 0000000..b5326d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 130724f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index a109280..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index c552644..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index f7edb49..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 7d5413a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
deleted file mode 100644
index 3155e632..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
deleted file mode 100644
index 01b003c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
deleted file mode 100644
index bffa0eb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
deleted file mode 100644
index 8884b48..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
deleted file mode 100644
index 695b80c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
deleted file mode 100644
index 1017e3b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
deleted file mode 100644
index 3651300..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
deleted file mode 100644
index 99533e0..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
deleted file mode 100644
index f4e5a12..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
deleted file mode 100644
index 467acd1..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
deleted file mode 100644
index 5418791..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
deleted file mode 100644
index f7f0f89..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
deleted file mode 100644
index c915426..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
deleted file mode 100644
index 5d36035..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
deleted file mode 100644
index da50305..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
deleted file mode 100644
index 8ee3421..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 184fa36..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index 79935bb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index d2099e6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index 2062aad..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
index fe29dea..b01c5e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
@@ -84,7 +84,7 @@
 
         switch (action) {
             case MotionEvent.ACTION_DOWN:
-                Slog.d("KeyButtonView", "press");
+                //Slog.d("KeyButtonView", "press");
                 mDownTime = SystemClock.uptimeMillis();
                 mRepeat = 0;
                 mSending = true;
@@ -132,7 +132,7 @@
         final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat,
                 0, 0, 0, flags, InputDevice.SOURCE_KEYBOARD);
         try {
-            Slog.d(StatusBarService.TAG, "injecting event " + ev);
+            //Slog.d(StatusBarService.TAG, "injecting event " + ev);
             mWindowManager.injectInputEventNoWait(ev);
         } catch (RemoteException ex) {
             // System process is dead
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
index e828f68..b4e0d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -36,6 +36,7 @@
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
+import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -91,6 +92,8 @@
 
     private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
 
+    private static final int INET_CONDITION_THRESHOLD = 50;
+
     private final Context mContext;
     private final StatusBarManager mService;
     private final Handler mHandler = new StatusBarHandler();
@@ -232,42 +235,62 @@
     };
 
     //***** Data connection icons
-    private int[] mDataIconList = sDataNetType_g;
+    private int[] mDataIconList = sDataNetType_g[0];
     //GSM/UMTS
-    private static final int[] sDataNetType_g = new int[] {
-            R.drawable.stat_sys_data_connected_g,
-            R.drawable.stat_sys_data_in_g,
-            R.drawable.stat_sys_data_out_g,
-            R.drawable.stat_sys_data_inandout_g,
+    private static final int[][] sDataNetType_g = {
+            { R.drawable.stat_sys_data_connected_g,
+              R.drawable.stat_sys_data_in_g,
+              R.drawable.stat_sys_data_out_g,
+              R.drawable.stat_sys_data_inandout_g },
+            { R.drawable.stat_sys_data_fully_connected_g,
+              R.drawable.stat_sys_data_fully_in_g,
+              R.drawable.stat_sys_data_fully_out_g,
+              R.drawable.stat_sys_data_fully_inandout_g }
         };
-    private static final int[] sDataNetType_3g = new int[] {
-            R.drawable.stat_sys_data_connected_3g,
-            R.drawable.stat_sys_data_in_3g,
-            R.drawable.stat_sys_data_out_3g,
-            R.drawable.stat_sys_data_inandout_3g,
+    private static final int[][] sDataNetType_3g = {
+            { R.drawable.stat_sys_data_connected_3g,
+              R.drawable.stat_sys_data_in_3g,
+              R.drawable.stat_sys_data_out_3g,
+              R.drawable.stat_sys_data_inandout_3g },
+            { R.drawable.stat_sys_data_fully_connected_3g,
+              R.drawable.stat_sys_data_fully_in_3g,
+              R.drawable.stat_sys_data_fully_out_3g,
+              R.drawable.stat_sys_data_fully_inandout_3g }
         };
-    private static final int[] sDataNetType_e = new int[] {
-            R.drawable.stat_sys_data_connected_e,
-            R.drawable.stat_sys_data_in_e,
-            R.drawable.stat_sys_data_out_e,
-            R.drawable.stat_sys_data_inandout_e,
+    private static final int[][] sDataNetType_e = {
+            { R.drawable.stat_sys_data_connected_e,
+              R.drawable.stat_sys_data_in_e,
+              R.drawable.stat_sys_data_out_e,
+              R.drawable.stat_sys_data_inandout_e },
+            { R.drawable.stat_sys_data_fully_connected_e,
+              R.drawable.stat_sys_data_fully_in_e,
+              R.drawable.stat_sys_data_fully_out_e,
+              R.drawable.stat_sys_data_fully_inandout_e }
         };
     //3.5G
-    private static final int[] sDataNetType_h = new int[] {
-            R.drawable.stat_sys_data_connected_h,
-            R.drawable.stat_sys_data_in_h,
-            R.drawable.stat_sys_data_out_h,
-            R.drawable.stat_sys_data_inandout_h,
+    private static final int[][] sDataNetType_h = {
+            { R.drawable.stat_sys_data_connected_h,
+              R.drawable.stat_sys_data_in_h,
+              R.drawable.stat_sys_data_out_h,
+              R.drawable.stat_sys_data_inandout_h },
+            { R.drawable.stat_sys_data_fully_connected_h,
+              R.drawable.stat_sys_data_fully_in_h,
+              R.drawable.stat_sys_data_fully_out_h,
+              R.drawable.stat_sys_data_fully_inandout_h }
     };
 
     //CDMA
     // Use 3G icons for EVDO data and 1x icons for 1XRTT data
-    private static final int[] sDataNetType_1x = new int[] {
-        R.drawable.stat_sys_data_connected_1x,
-        R.drawable.stat_sys_data_in_1x,
-        R.drawable.stat_sys_data_out_1x,
-        R.drawable.stat_sys_data_inandout_1x,
-    };
+    private static final int[][] sDataNetType_1x = {
+            { R.drawable.stat_sys_data_connected_1x,
+              R.drawable.stat_sys_data_in_1x,
+              R.drawable.stat_sys_data_out_1x,
+              R.drawable.stat_sys_data_inandout_1x },
+            { R.drawable.stat_sys_data_fully_connected_1x,
+              R.drawable.stat_sys_data_fully_in_1x,
+              R.drawable.stat_sys_data_fully_out_1x,
+              R.drawable.stat_sys_data_fully_inandout_1x }
+            };
 
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
@@ -292,17 +315,22 @@
     private boolean mBluetoothEnabled;
 
     // wifi
-    private static final int[] sWifiSignalImages = new int[] {
-            R.drawable.stat_sys_wifi_signal_1,
-            R.drawable.stat_sys_wifi_signal_2,
-            R.drawable.stat_sys_wifi_signal_3,
-            R.drawable.stat_sys_wifi_signal_4,
+    private static final int[][] sWifiSignalImages = {
+            { R.drawable.stat_sys_wifi_signal_1,
+              R.drawable.stat_sys_wifi_signal_2,
+              R.drawable.stat_sys_wifi_signal_3,
+              R.drawable.stat_sys_wifi_signal_4 },
+            { R.drawable.stat_sys_wifi_signal_1_fully,
+              R.drawable.stat_sys_wifi_signal_2_fully,
+              R.drawable.stat_sys_wifi_signal_3_fully,
+              R.drawable.stat_sys_wifi_signal_4_fully }
         };
     private static final int sWifiTemporarilyNotConnectedImage =
             R.drawable.stat_sys_wifi_signal_0;
 
     private int mLastWifiSignalLevel = -1;
     private boolean mIsWifiConnected = false;
+    private int mLastWifiInetConnectivityState = 0;
 
     // sync state
     // If sync is active the SyncActive icon is displayed. If sync is not active but
@@ -353,6 +381,10 @@
             else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
                 updateTTY(intent);
             }
+            else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                // TODO - stop using other means to get wifi/mobile info
+                updateConnectivity(intent);
+            }
         }
     };
 
@@ -389,7 +421,7 @@
         mService.setIconVisibility("data_connection", false);
 
         // wifi
-        mService.setIcon("wifi", sWifiSignalImages[0], 0);
+        mService.setIcon("wifi", sWifiSignalImages[0][0], 0);
         mService.setIconVisibility("wifi", false);
         // wifi will get updated by the sticky intents
 
@@ -456,6 +488,7 @@
         filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
         // load config to determine if to distinguish Hspa data icon
@@ -659,6 +692,50 @@
         }
     }
 
+    private void updateConnectivity(Intent intent) {
+        NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
+                ConnectivityManager.EXTRA_NETWORK_INFO));
+        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
+        Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus);
+        if (info.isConnected() == false) return;
+
+        switch (info.getType()) {
+        case ConnectivityManager.TYPE_MOBILE:
+            if (info.isConnected()) {
+                updateDataNetType(info.getSubtype(), connectionStatus);
+                updateDataIcon();
+            }
+            break;
+        case ConnectivityManager.TYPE_WIFI:
+            if (info.isConnected()) {
+                mIsWifiConnected = true;
+                mLastWifiInetConnectivityState =
+                        (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
+                int iconId;
+                if (mLastWifiSignalLevel == -1) {
+                    iconId = sWifiSignalImages[mLastWifiInetConnectivityState][0];
+                } else {
+                    iconId = sWifiSignalImages[mLastWifiInetConnectivityState]
+                            [mLastWifiSignalLevel];
+                }
+
+                mService.setIcon("wifi", iconId, 0);
+                // Show the icon since wi-fi is connected
+                mService.setIconVisibility("wifi", true);
+            } else {
+                mLastWifiSignalLevel = -1;
+                mIsWifiConnected = false;
+                mLastWifiInetConnectivityState = 0;
+                int iconId = sWifiSignalImages[0][0];
+
+                mService.setIcon("wifi", iconId, 0);
+                // Hide the icon since we're not connected
+                mService.setIconVisibility("wifi", false);
+            }
+            break;
+        }
+    }
+
     private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         @Override
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
@@ -686,7 +763,7 @@
         @Override
         public void onDataConnectionStateChanged(int state, int networkType) {
             mDataState = state;
-            updateDataNetType(networkType);
+            updateDataNetType(networkType, 0);
             updateDataIcon();
         }
 
@@ -848,37 +925,38 @@
         return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
     }
 
-    private final void updateDataNetType(int net) {
+    private final void updateDataNetType(int net, int inetCondition) {
+        int connected = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0);
         switch (net) {
         case TelephonyManager.NETWORK_TYPE_EDGE:
-            mDataIconList = sDataNetType_e;
+            mDataIconList = sDataNetType_e[connected];
             break;
         case TelephonyManager.NETWORK_TYPE_UMTS:
-            mDataIconList = sDataNetType_3g;
+            mDataIconList = sDataNetType_3g[connected];
             break;
         case TelephonyManager.NETWORK_TYPE_HSDPA:
         case TelephonyManager.NETWORK_TYPE_HSUPA:
         case TelephonyManager.NETWORK_TYPE_HSPA:
             if (mHspaDataDistinguishable) {
-                mDataIconList = sDataNetType_h;
+                mDataIconList = sDataNetType_h[connected];
             } else {
-                mDataIconList = sDataNetType_3g;
+                mDataIconList = sDataNetType_3g[connected];
             }
             break;
         case TelephonyManager.NETWORK_TYPE_CDMA:
             // display 1xRTT for IS95A/B
-            mDataIconList = this.sDataNetType_1x;
+            mDataIconList = sDataNetType_1x[connected];
             break;
         case TelephonyManager.NETWORK_TYPE_1xRTT:
-            mDataIconList = this.sDataNetType_1x;
+            mDataIconList = sDataNetType_1x[connected];
             break;
         case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
         case TelephonyManager.NETWORK_TYPE_EVDO_A:
         case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            mDataIconList = sDataNetType_3g;
+            mDataIconList = sDataNetType_3g[connected];
             break;
         default:
-            mDataIconList = sDataNetType_g;
+            mDataIconList = sDataNetType_g[connected];
         break;
         }
     }
@@ -1019,34 +1097,6 @@
             if (!enabled) {
                 mService.setIconVisibility("wifi", false);
             }
-        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-
-            final NetworkInfo networkInfo = (NetworkInfo)
-                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-
-            int iconId;
-            if (networkInfo != null && networkInfo.isConnected()) {
-                mIsWifiConnected = true;
-                if (mLastWifiSignalLevel == -1) {
-                    iconId = sWifiSignalImages[0];
-                } else {
-                    iconId = sWifiSignalImages[mLastWifiSignalLevel];
-                }
-
-                mService.setIcon("wifi", iconId, 0);
-                // Show the icon since wi-fi is connected
-                mService.setIconVisibility("wifi", true);
-
-            } else {
-                mLastWifiSignalLevel = -1;
-                mIsWifiConnected = false;
-                iconId = sWifiSignalImages[0];
-
-                mService.setIcon("wifi", iconId, 0);
-                // Hide the icon since we're not connected
-                mService.setIconVisibility("wifi", false);
-            }
-
         } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
             int iconId;
             final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
@@ -1055,7 +1105,7 @@
             if (newSignalLevel != mLastWifiSignalLevel) {
                 mLastWifiSignalLevel = newSignalLevel;
                 if (mIsWifiConnected) {
-                    iconId = sWifiSignalImages[newSignalLevel];
+                    iconId = sWifiSignalImages[mLastWifiInetConnectivityState][newSignalLevel];
                 } else {
                     iconId = sWifiTemporarilyNotConnectedImage;
                 }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index d1fbf17..e5889bf 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -567,16 +567,10 @@
     if (checkPidAndHardware() != NO_ERROR) return;
 
     mPreviewCallbackFlag = callback_flag;
-
-    // If we don't use overlay, we always need the preview frame for display.
-    // If we do use overlay, we only need the preview frame if the user
-    // wants the data.
-    if (mUseOverlay) {
-        if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
-            enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        } else {
-            disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        }
+    if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+        enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+    } else {
+        disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     }
 }
 
@@ -636,7 +630,6 @@
     } else {
         // XXX: Set the orientation of the ANativeWindow.
         mHardware->setPreviewWindow(mPreviewWindow);
-        enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
         result = mHardware->startPreview();
     }
     return result;
@@ -1025,9 +1018,7 @@
         mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
                                   FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
                                   FRAME_CALLBACK_FLAG_ENABLE_MASK);
-        if (mUseOverlay) {
-            disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        }
+        disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     }
 
     if (c != 0) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b6d725f..96a239d 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -102,6 +102,11 @@
     private Context mContext;
     private int mNetworkPreference;
     private int mActiveDefaultNetwork = -1;
+    // 0 is full bad, 100 is full good
+    private int mDefaultInetCondition = 0;
+    private int mDefaultInetConditionPublished = 0;
+    private boolean mInetConditionChangeInFlight = false;
+    private int mDefaultConnectionSequence = 0;
 
     private int mNumDnsEntries;
 
@@ -1077,6 +1082,7 @@
             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
                     info.getExtraInfo());
         }
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         sendStickyBroadcast(intent);
     }
 
@@ -1203,6 +1209,14 @@
                 }
             }
             mActiveDefaultNetwork = type;
+            // this will cause us to come up initially as unconnected and switching
+            // to connected after our normal pause unless somebody reports us as reall
+            // disconnected
+            mDefaultInetConditionPublished = 0;
+            mDefaultConnectionSequence++;
+            mInetConditionChangeInFlight = false;
+            // Don't do this - if we never sign in stay, grey
+            //reportNetworkCondition(mActiveDefaultNetwork, 100);
         }
         thisNet.setTeardownRequested(false);
         updateNetworkSettings(thisNet);
@@ -1637,6 +1651,70 @@
                                 causedBy + " released by timeout");
                     }
                     break;
+                case NetworkStateTracker.EVENT_INET_CONDITION_CHANGE:
+                    if (DBG) {
+                        Slog.d(TAG, "Inet connectivity change, net=" +
+                                msg.arg1 + ", condition=" + msg.arg2 +
+                                ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
+                    }
+                    if (mActiveDefaultNetwork == -1) {
+                        if (DBG) Slog.d(TAG, "no active default network - aborting");
+                        break;
+                    }
+                    if (mActiveDefaultNetwork != msg.arg1) {
+                        if (DBG) Slog.d(TAG, "given net not default - aborting");
+                        break;
+                    }
+                    mDefaultInetCondition = msg.arg2;
+                    int delay;
+                    if (mInetConditionChangeInFlight == false) {
+                        if (DBG) Slog.d(TAG, "starting a change hold");
+                        // setup a new hold to debounce this
+                        if (mDefaultInetCondition > 50) {
+                            delay = Settings.Secure.getInt(mContext.getContentResolver(),
+                                    Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
+                        } else {
+                            delay = Settings.Secure.getInt(mContext.getContentResolver(),
+                                    Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
+                        }
+                        mInetConditionChangeInFlight = true;
+                        sendMessageDelayed(obtainMessage(
+                                NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END,
+                                mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
+                    } else {
+                        // we've set the new condition, when this hold ends that will get
+                        // picked up
+                        if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt");
+                    }
+                    break;
+                case NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END:
+                    if (DBG) {
+                        Slog.d(TAG, "Inet hold end, net=" + msg.arg1 +
+                                ", condition =" + mDefaultInetCondition +
+                                ", published condition =" + mDefaultInetConditionPublished);
+                    }
+                    mInetConditionChangeInFlight = false;
+
+                    if (mActiveDefaultNetwork == -1) {
+                        if (DBG) Slog.d(TAG, "no active default network - aborting");
+                        break;
+                    }
+                    if (mDefaultConnectionSequence != msg.arg2) {
+                        if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting");
+                        break;
+                    }
+                    if (mDefaultInetConditionPublished == mDefaultInetCondition) {
+                        if (DBG) Slog.d(TAG, "no change in condition - aborting");
+                        break;
+                    }
+                    NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
+                    if (networkInfo.isConnected() == false) {
+                        if (DBG) Slog.d(TAG, "default network not connected - aborting");
+                        break;
+                    }
+                    mDefaultInetConditionPublished = mDefaultInetCondition;
+                    sendConnectedBroadcast(networkInfo);
+                    break;
             }
         }
     }
@@ -1748,4 +1826,15 @@
                 mNetTransitionWakeLockTimeout);
         return;
     }
+
+    // 100 percent is full good, 0 is full bad.
+    public void reportInetCondition(int networkType, int percentage) {
+        if (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")");
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.STATUS_BAR,
+                "ConnectivityService");
+
+        mHandler.sendMessage(mHandler.obtainMessage(
+            NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage));
+    }
 }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 9d262b6..5afabbd 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -113,6 +113,10 @@
     private boolean mScreenOn = true;
     private boolean mInCall = false;
     private boolean mNotificationPulseEnabled;
+    // This is true if we have received a new notification while the screen is off
+    // (that is, if mLedNotification was set while the screen was off)
+    // This is reset to false when the screen is turned on.
+    private boolean mPendingPulseNotification;
 
     // for adb connected notifications
     private boolean mAdbNotificationShown = false;
@@ -1098,6 +1102,11 @@
             mBatteryLight.turnOff();
         }
 
+        // clear pending pulse notification if screen is on
+        if (mScreenOn || mLedNotification == null) {
+            mPendingPulseNotification = false;
+        }
+
         // handle notification lights
         if (mLedNotification == null) {
             // get next notification, if any
@@ -1105,11 +1114,14 @@
             if (n > 0) {
                 mLedNotification = mLights.get(n-1);
             }
+            if (mLedNotification != null && !mScreenOn) {
+                mPendingPulseNotification = true;
+            }
         }
 
         // we only flash if screen is off and persistent pulsing is enabled
         // and we are not currently in a call
-        if (mLedNotification == null || mScreenOn || mInCall) {
+        if (!mPendingPulseNotification || mScreenOn || mInCall) {
             mNotificationLight.turnOff();
         } else {
             int ledARGB = mLedNotification.notification.ledARGB;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 5ae87cf..f6d92b5 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -9408,7 +9408,12 @@
         } catch (NoSuchAlgorithmException nsae) {
             Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
             return null;
+        } catch (IOException ioe) {
+            Slog.e(TAG, "Failed to retrieve encryption keys with exception: "
+                      + ioe);
+            return null;
         }
+
     }
 
     /* package */ static String getTempContainerId() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7d8c307..1a7e944 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -753,6 +753,7 @@
     boolean mWaitingUpdate = false;
     boolean mDidUpdate = false;
     boolean mOnBattery = false;
+    boolean mLaunchWarningShown = false;
 
     Context mContext;
 
@@ -2907,6 +2908,30 @@
         }
     }
 
+    final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
+        if (!mLaunchWarningShown) {
+            mLaunchWarningShown = true;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (ActivityManagerService.this) {
+                        final Dialog d = new LaunchWarningWindow(mContext, cur, next);
+                        d.show();
+                        mHandler.postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                synchronized (ActivityManagerService.this) {
+                                    d.dismiss();
+                                    mLaunchWarningShown = false;
+                                }
+                            }
+                        }, 4000);
+                    }
+                }
+            });
+        }
+    }
+    
     final void decPersistentCountLocked(ProcessRecord app) {
         app.persistentActivities--;
         if (app.persistentActivities > 0) {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 62be918..bf4db80 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -34,6 +34,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.view.IApplicationToken;
 
 import java.io.PrintWriter;
@@ -68,7 +69,8 @@
     int icon;               // resource identifier of activity's icon.
     int theme;              // resource identifier of activity's theme.
     TaskRecord task;        // the task this is in.
-    long startTime;         // when we starting launching this activity
+    long launchTime;        // when we starting launching this activity
+    long startTime;         // last time this activity was started
     long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
     Configuration configuration; // configuration activity was last running in
     ActivityRecord resultTo; // who started this entry, so will get our reply
@@ -167,6 +169,11 @@
                 pw.print(" frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
                 pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
                 pw.print(" idle="); pw.println(idle);
+        if (launchTime != 0 || startTime != 0) {
+            pw.print(prefix); pw.print("launchTime=");
+                    TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime=");
+                    TimeUtils.formatDuration(startTime, pw); pw.println("");
+        }
         if (waitingVisible || nowVisible) {
             pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
                     pw.print(" nowVisible="); pw.println(nowVisible);
@@ -422,9 +429,9 @@
     
     public void windowsVisible() {
         synchronized(service) {
-            if (startTime != 0) {
+            if (launchTime != 0) {
                 final long curTime = SystemClock.uptimeMillis();
-                final long thisTime = curTime - startTime;
+                final long thisTime = curTime - launchTime;
                 final long totalTime = stack.mInitialStartTime != 0
                         ? (curTime - stack.mInitialStartTime) : thisTime;
                 if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
@@ -433,22 +440,24 @@
                             thisTime, totalTime);
                     StringBuilder sb = service.mStringBuilder;
                     sb.setLength(0);
-                    sb.append("Displayed activity ");
+                    sb.append("Displayed ");
                     sb.append(shortComponentName);
                     sb.append(": ");
-                    sb.append(thisTime);
-                    sb.append(" ms (total ");
+                    TimeUtils.formatDuration(thisTime, sb);
+                    sb.append(" (total ");
+                    TimeUtils.formatDuration(totalTime, sb);
                     sb.append(totalTime);
-                    sb.append(" ms)");
+                    sb.append(")");
                     Log.i(ActivityManagerService.TAG, sb.toString());
                 }
                 stack.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
                 if (totalTime > 0) {
                     service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
                 }
-                startTime = 0;
+                launchTime = 0;
                 stack.mInitialStartTime = 0;
             }
+            startTime = 0;
             stack.reportActivityVisibleLocked(this);
             if (ActivityManagerService.DEBUG_SWITCH) Log.v(
                     ActivityManagerService.TAG, "windowsVisible(): " + this);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 5f79b85..a0c21dd 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -102,6 +102,10 @@
     // 30 minutes.
     static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
     
+    // How long between activity launches that we consider safe to not warn
+    // the user about an unexpected activity being launched on top.
+    static final long START_WARN_TIME = 5*1000;
+    
     // Set to false to disable the preview that is shown while a new activity
     // is being started.
     static final boolean SHOW_APP_STARTING_PREVIEW = true;
@@ -213,6 +217,13 @@
     ActivityRecord mResumedActivity = null;
     
     /**
+     * This is the last activity that has been started.  It is only used to
+     * identify when multiple activities are started at once so that the user
+     * can be warned they may not be in the activity they think they are.
+     */
+    ActivityRecord mLastStartedActivity = null;
+    
+    /**
      * Set when we know we are going to be calling updateConfiguration()
      * soon, so want to skip intermediate config checks.
      */
@@ -586,10 +597,10 @@
         ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                 r.info.applicationInfo.uid);
         
-        if (r.startTime == 0) {
-            r.startTime = SystemClock.uptimeMillis();
+        if (r.launchTime == 0) {
+            r.launchTime = SystemClock.uptimeMillis();
             if (mInitialStartTime == 0) {
-                mInitialStartTime = r.startTime;
+                mInitialStartTime = r.launchTime;
             }
         } else if (mInitialStartTime == 0) {
             mInitialStartTime = SystemClock.uptimeMillis();
@@ -1090,6 +1101,31 @@
             return false;
         }
 
+        // Okay we are now going to start a switch, to 'next'.  We may first
+        // have to pause the current activity, but this is an important point
+        // where we have decided to go to 'next' so keep track of that.
+        if (mLastStartedActivity != null) {
+            long now = SystemClock.uptimeMillis();
+            final boolean inTime = mLastStartedActivity.startTime != 0
+                    && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
+            final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
+            final int nextUid = next.info.applicationInfo.uid;
+            if (inTime && lastUid != nextUid
+                    && lastUid != next.launchedFromUid
+                    && mService.checkPermission(
+                            android.Manifest.permission.STOP_APP_SWITCHES,
+                            -1, next.launchedFromUid)
+                    != PackageManager.PERMISSION_GRANTED) {
+                mService.showLaunchWarningLocked(mLastStartedActivity, next);
+            } else {
+                next.startTime = now;
+                mLastStartedActivity = next;
+            }
+        } else {
+            next.startTime = SystemClock.uptimeMillis();
+            mLastStartedActivity = next;
+        }
+        
         // We need to start pausing the current activity so the top one
         // can be resumed...
         if (mResumedActivity != null) {
@@ -1314,7 +1350,6 @@
         
         if (!newTask) {
             // If starting in an existing task, find where that is...
-            ActivityRecord next = null;
             boolean startIt = true;
             for (int i = NH-1; i >= 0; i--) {
                 ActivityRecord p = (ActivityRecord)mHistory.get(i);
@@ -1342,14 +1377,13 @@
                 if (p.fullscreen) {
                     startIt = false;
                 }
-                next = p;
             }
         }
 
         // Place a new activity at top of stack, so it is next to interact
         // with the user.
         if (addPos < 0) {
-            addPos = mHistory.size();
+            addPos = NH;
         }
         
         // If we are not placing the new activity frontmost, we do not want
diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/java/com/android/server/am/LaunchWarningWindow.java
new file mode 100644
index 0000000..4130e33
--- /dev/null
+++ b/services/java/com/android/server/am/LaunchWarningWindow.java
@@ -0,0 +1,36 @@
+package com.android.server.am;
+
+import com.android.internal.R;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class LaunchWarningWindow extends Dialog {
+    public LaunchWarningWindow(Context context, ActivityRecord cur, ActivityRecord next) {
+        super(context, R.style.Theme_Toast);
+
+        requestWindowFeature(Window.FEATURE_LEFT_ICON);
+        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+        
+        setContentView(R.layout.launch_warning);
+        setTitle(context.getText(R.string.launch_warning_title));
+        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
+                R.drawable.ic_dialog_alert);
+        ImageView icon = (ImageView)findViewById(R.id.replace_app_icon);
+        icon.setImageDrawable(next.info.applicationInfo.loadIcon(context.getPackageManager()));
+        TextView text = (TextView)findViewById(R.id.replace_message);
+        text.setText(context.getResources().getString(R.string.launch_warning_replace,
+                next.info.applicationInfo.loadLabel(context.getPackageManager()).toString()));
+        icon = (ImageView)findViewById(R.id.original_app_icon);
+        icon.setImageDrawable(cur.info.applicationInfo.loadIcon(context.getPackageManager()));
+        text = (TextView)findViewById(R.id.original_message);
+        text.setText(context.getResources().getString(R.string.launch_warning_original,
+                cur.info.applicationInfo.loadLabel(context.getPackageManager()).toString()));
+    }
+}
diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java
index 70ff9ea..2f7ddc4 100644
--- a/services/java/com/android/server/sip/SipSessionGroup.java
+++ b/services/java/com/android/server/sip/SipSessionGroup.java
@@ -25,6 +25,7 @@
 import android.net.sip.ISipSession;
 import android.net.sip.ISipSessionListener;
 import android.net.sip.SessionDescription;
+import android.net.sip.SipErrorCode;
 import android.net.sip.SipProfile;
 import android.net.sip.SipSessionAdapter;
 import android.net.sip.SipSessionState;
@@ -34,6 +35,7 @@
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.DatagramSocket;
+import java.net.UnknownHostException;
 import java.text.ParseException;
 import java.util.Collection;
 import java.util.EventObject;
@@ -60,6 +62,7 @@
 import javax.sip.Transaction;
 import javax.sip.TransactionState;
 import javax.sip.TransactionTerminatedEvent;
+import javax.sip.TransactionUnavailableException;
 import javax.sip.address.Address;
 import javax.sip.address.SipURI;
 import javax.sip.header.CSeqHeader;
@@ -77,6 +80,7 @@
 class SipSessionGroup implements SipListener {
     private static final String TAG = "SipSession";
     private static final String ANONYMOUS = "anonymous";
+    private static final String SERVER_ERROR_PREFIX = "Response: ";
     private static final int EXPIRY_TIME = 3600;
 
     private static final EventObject DEREGISTER = new EventObject("Deregister");
@@ -282,7 +286,7 @@
                 Log.d(TAG, "event not processed: " + event);
             }
         } catch (Throwable e) {
-            Log.e(TAG, "event process error: " + event, e);
+            Log.w(TAG, "event process error: " + event, e);
             session.onError(e);
         }
     }
@@ -407,6 +411,7 @@
                         try {
                             processCommand(command);
                         } catch (SipException e) {
+                            Log.w(TAG, "command error: " + command, e);
                             // TODO: find a better way to do this
                             if ((command instanceof RegisterCommand)
                                     || (command == DEREGISTER)) {
@@ -603,7 +608,7 @@
             case INCOMING_CALL:
             case INCOMING_CALL_ANSWERING:
             case OUTGOING_CALL_CANCELING:
-                endCallOnError(new SipException("timed out"));
+                endCallOnError(SipErrorCode.TIME_OUT, event.toString());
                 break;
             case PINGING:
                 reset();
@@ -691,15 +696,11 @@
                     return true;
                 case Response.UNAUTHORIZED:
                 case Response.PROXY_AUTHENTICATION_REQUIRED:
-                    String nonce = getNonceFromResponse(response);
-                    if (((nonce != null) && nonce.equals(mLastNonce)) ||
-                            (nonce == mLastNonce)) {
+                    if (!handleAuthentication(event)) {
                         Log.v(TAG, "Incorrect username/password");
                         reset();
-                        onRegistrationFailed(createCallbackException(response));
-                    } else {
-                        mSipHelper.handleChallenge(event, getAccountManager());
-                        mLastNonce = nonce;
+                        onRegistrationFailed(SipErrorCode.INVALID_CREDENTIALS,
+                                "incorrect username or password");
                     }
                     return true;
                 default:
@@ -713,6 +714,23 @@
             return false;
         }
 
+        private boolean handleAuthentication(ResponseEvent event)
+                throws SipException {
+            Response response = event.getResponse();
+            String nonce = getNonceFromResponse(response);
+            if (((nonce != null) && nonce.equals(mLastNonce)) ||
+                    (nonce == mLastNonce)) {
+                Log.v(TAG, "Incorrect username/password");
+                return false;
+            } else {
+                mClientTransaction = mSipHelper.handleChallenge(
+                        event, getAccountManager());
+                mDialog = mClientTransaction.getDialog();
+                mLastNonce = nonce;
+                return true;
+            }
+        }
+
         private AccountManager getAccountManager() {
             return new AccountManager() {
                 public UserCredentials getCredentials(ClientTransaction
@@ -833,14 +851,12 @@
                     establishCall();
                     return true;
                 case Response.PROXY_AUTHENTICATION_REQUIRED:
-                    mClientTransaction = mSipHelper.handleChallenge(
-                            (ResponseEvent) evt, getAccountManager());
-                    mDialog = mClientTransaction.getDialog();
-                    addSipSession(this);
-                    return true;
-                case Response.BUSY_HERE:
-                    reset();
-                    mProxy.onCallBusy(this);
+                    if (handleAuthentication(event)) {
+                        addSipSession(this);
+                    } else {
+                        endCallOnError(SipErrorCode.INVALID_CREDENTIALS,
+                                "incorrect username or password");
+                    }
                     return true;
                 case Response.REQUEST_PENDING:
                     // TODO:
@@ -849,7 +865,7 @@
                 default:
                     if (statusCode >= 400) {
                         // error: an ack is sent automatically by the stack
-                        onError(createCallbackException(response));
+                        onError(response);
                         return true;
                     } else if (statusCode >= 300) {
                         // TODO: handle 3xx (redirect)
@@ -933,9 +949,13 @@
             return false;
         }
 
+        private String createErrorMessage(Response response) {
+            return String.format(SERVER_ERROR_PREFIX + "%s (%d)",
+                    response.getReasonPhrase(), response.getStatusCode());
+        }
+
         private Exception createCallbackException(Response response) {
-            return new SipException(String.format("Response: %s (%d)",
-                    response.getReasonPhrase(), response.getStatusCode()));
+            return new SipException(createErrorMessage(response));
         }
 
         private void establishCall() {
@@ -946,8 +966,9 @@
 
         private void fallbackToPreviousInCall(Throwable exception) {
             mState = SipSessionState.IN_CALL;
-            mProxy.onCallChangeFailed(this, exception.getClass().getName(),
-                    exception.getMessage());
+            exception = getRootCause(exception);
+            mProxy.onCallChangeFailed(this, getErrorCode(exception).toString(),
+                    exception.toString());
         }
 
         private void endCallNormally() {
@@ -956,9 +977,18 @@
         }
 
         private void endCallOnError(Throwable exception) {
+            exception = getRootCause(exception);
+            endCallOnError(getErrorCode(exception), exception.toString());
+        }
+
+        private void endCallOnError(SipErrorCode errorCode, String message) {
             reset();
-            mProxy.onError(this, exception.getClass().getName(),
-                    exception.getMessage());
+            mProxy.onError(this, errorCode.toString(), message);
+        }
+
+        private void endCallOnBusy() {
+            reset();
+            mProxy.onCallBusy(this);
         }
 
         private void onError(Throwable exception) {
@@ -969,13 +999,72 @@
             }
         }
 
+        private void onError(Response response) {
+            if (mInCall) {
+                fallbackToPreviousInCall(createCallbackException(response));
+            } else {
+                int statusCode = response.getStatusCode();
+                if ((statusCode == Response.TEMPORARILY_UNAVAILABLE)
+                        || (statusCode == Response.BUSY_HERE)) {
+                    endCallOnBusy();
+                } else {
+                    endCallOnError(getErrorCode(statusCode),
+                            createErrorMessage(response));
+                }
+            }
+        }
+
+        private SipErrorCode getErrorCode(int responseStatusCode) {
+            switch (responseStatusCode) {
+                case Response.NOT_FOUND:
+                case Response.ADDRESS_INCOMPLETE:
+                    return SipErrorCode.INVALID_REMOTE_URI;
+                case Response.REQUEST_TIMEOUT:
+                    return SipErrorCode.TIME_OUT;
+                default:
+                    if (responseStatusCode < 500) {
+                        return SipErrorCode.CLIENT_ERROR;
+                    } else {
+                        return SipErrorCode.SERVER_ERROR;
+                    }
+            }
+        }
+
+        private Throwable getRootCause(Throwable exception) {
+            Throwable cause = exception.getCause();
+            while (cause != null) {
+                exception = cause;
+                cause = exception.getCause();
+            }
+            return exception;
+        }
+
+        private SipErrorCode getErrorCode(Throwable exception) {
+            String message = exception.getMessage();
+            if (exception instanceof UnknownHostException) {
+                return SipErrorCode.INVALID_REMOTE_URI;
+            } else if (exception instanceof IOException) {
+                return SipErrorCode.SOCKET_ERROR;
+            } else if (message.startsWith(SERVER_ERROR_PREFIX)) {
+                return SipErrorCode.SERVER_ERROR;
+            } else {
+                return SipErrorCode.CLIENT_ERROR;
+            }
+        }
+
         private void onRegistrationDone(int duration) {
             mProxy.onRegistrationDone(this, duration);
         }
 
+        private void onRegistrationFailed(SipErrorCode errorCode,
+                String message) {
+            mProxy.onRegistrationFailed(this, errorCode.toString(), message);
+        }
+
         private void onRegistrationFailed(Throwable exception) {
-            mProxy.onRegistrationFailed(this, exception.getClass().getName(),
-                    exception.getMessage());
+            exception = getRootCause(exception);
+            onRegistrationFailed(getErrorCode(exception),
+                    exception.toString());
         }
     }
 
diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java
index 7234196..747d79f 100644
--- a/services/java/com/android/server/sip/SipSessionListenerProxy.java
+++ b/services/java/com/android/server/sip/SipSessionListenerProxy.java
@@ -124,12 +124,12 @@
     }
 
     public void onCallChangeFailed(final ISipSession session,
-            final String className, final String message) {
+            final String errorCode, final String message) {
         if (mListener == null) return;
         proxy(new Runnable() {
             public void run() {
                 try {
-                    mListener.onCallChangeFailed(session, className, message);
+                    mListener.onCallChangeFailed(session, errorCode, message);
                 } catch (Throwable t) {
                     handle(t, "onCallChangeFailed()");
                 }
@@ -137,13 +137,13 @@
         });
     }
 
-    public void onError(final ISipSession session, final String className,
+    public void onError(final ISipSession session, final String errorCode,
             final String message) {
         if (mListener == null) return;
         proxy(new Runnable() {
             public void run() {
                 try {
-                    mListener.onError(session, className, message);
+                    mListener.onError(session, errorCode, message);
                 } catch (Throwable t) {
                     handle(t, "onError()");
                 }
@@ -179,12 +179,12 @@
     }
 
     public void onRegistrationFailed(final ISipSession session,
-            final String className, final String message) {
+            final String errorCode, final String message) {
         if (mListener == null) return;
         proxy(new Runnable() {
             public void run() {
                 try {
-                    mListener.onRegistrationFailed(session, className, message);
+                    mListener.onRegistrationFailed(session, errorCode, message);
                 } catch (Throwable t) {
                     handle(t, "onRegistrationFailed()");
                 }
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 166c528..3e23929 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -292,6 +292,9 @@
 void DisplayHardware::releaseScreen() const
 {
     DisplayHardwareBase::releaseScreen();
+    if (mHwc->initCheck() == NO_ERROR) {
+        mHwc->release();
+    }
 }
 
 void DisplayHardware::acquireScreen() const
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0291d78..129be4e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -87,6 +87,11 @@
     return (status_t)err;
 }
 
+status_t HWComposer::release() const {
+    int err = mHwc->set(mHwc, NULL, NULL, NULL);
+    return (status_t)err;
+}
+
 size_t HWComposer::getNumLayers() const {
     return mList ? mList->numHwLayers : 0;
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c5d5c2b..22ff10c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -48,6 +48,8 @@
     // commits the list
     status_t commit() const;
 
+    // release hardware resources
+    status_t release() const;
 
     size_t getNumLayers() const;
     hwc_layer_t* getLayers() const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a78d9b9..d820380 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -383,10 +383,10 @@
         // inform the h/w that we're done compositing
         hw.compositionComplete();
 
-        // release the clients before we flip ('cause flip might block)
+        postFramebuffer();
+
         unlockClients();
 
-        postFramebuffer();
     } else {
         // pretend we did the post
         unlockClients();
@@ -885,8 +885,8 @@
      */
     for (size_t i=0 ; i<count ; i++) {
         if (cur) {
-            if (!(cur[i].compositionType == HWC_FRAMEBUFFER) ||
-                    cur[i].flags & HWC_SKIP_LAYER) {
+            if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
+                !(cur[i].flags & HWC_SKIP_LAYER)) {
                 // skip layers handled by the HAL
                 continue;
             }
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index d899430..0746562 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -53,6 +53,10 @@
     public static final int ENCODING_7BIT = 1;
     public static final int ENCODING_8BIT = 2;
     public static final int ENCODING_16BIT = 3;
+    /**
+     * @hide This value is not defined in global standard. Only in Korea, this is used.
+     */
+    public static final int ENCODING_KSC5601 = 4;
 
     /** The maximum number of payload bytes per message */
     public static final int MAX_USER_DATA_BYTES = 140;
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index 11d0b1b..e5456e4 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -39,6 +39,7 @@
         CONGESTION,                     /* outgoing call to congested network */
         MMI,                            /* not presently used; dial() returns null */
         INVALID_NUMBER,                 /* invalid dial string */
+        INVALID_CREDENTIALS,            /* invalid credentials */
         LOST_SIGNAL,
         LIMIT_EXCEEDED,                 /* eg GSM ACM limit exceeded */
         INCOMING_REJECTED,              /* an incoming call that was rejected */
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 75ea116..e42827f 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -16,10 +16,14 @@
 
 package com.android.internal.telephony;
 
+import android.text.TextUtils;
 import android.util.SparseIntArray;
 
 import android.util.Log;
 
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
 /**
  * This class implements the character set mapping between
  * the GSM SMS 7-bit alphabet specified in TS 23.038 6.2.1
@@ -354,6 +358,32 @@
      */
     public static String
     gsm8BitUnpackedToString(byte[] data, int offset, int length) {
+        return gsm8BitUnpackedToString(data, offset, length, "");
+    }
+
+    /**
+     * Convert a GSM alphabet string that's stored in 8-bit unpacked
+     * format (as it often appears in SIM records) into a String
+     *
+     * Field may be padded with trailing 0xff's. The decode stops
+     * at the first 0xff encountered.
+     *
+     * Additionally, in some country(ex. Korea), there are non-ASCII or MBCS characters.
+     * If a character set is given, characters in data are treat as MBCS.
+     */
+    public static String
+    gsm8BitUnpackedToString(byte[] data, int offset, int length, String characterset) {
+        boolean isMbcs = false;
+        Charset charset = null;
+        ByteBuffer mbcsBuffer = null;
+
+        if (!TextUtils.isEmpty(characterset)
+                && !characterset.equalsIgnoreCase("us-ascii")
+                && Charset.isSupported(characterset)) {
+            isMbcs = true;
+            charset = Charset.forName(characterset);
+            mbcsBuffer = ByteBuffer.allocate(2);
+        }
         boolean prevWasEscape;
         StringBuilder ret = new StringBuilder(length);
 
@@ -379,7 +409,15 @@
                 if (prevWasEscape) {
                     ret.append((char)gsmExtendedToChar.get(c, ' '));
                 } else {
-                    ret.append((char)gsmToChar.get(c, ' '));
+                    if (!isMbcs || c < 0x80 || i + 1 >= offset + length) {
+                        ret.append((char)gsmToChar.get(c, ' '));
+                    } else {
+                        // isMbcs must be true. So both mbcsBuffer and charset are initialized.
+                        mbcsBuffer.clear();
+                        mbcsBuffer.put(data, i++, 2);
+                        mbcsBuffer.flip();
+                        ret.append(charset.decode(mbcsBuffer).toString());
+                    }
                 }
                 prevWasEscape = false;
             }
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 005ae37..df579b0 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -16,13 +16,16 @@
 
 package com.android.internal.telephony;
 
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.util.Log;
 
 import com.android.internal.telephony.GsmAlphabet;
-
 import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 
 /**
  * Various methods, useful for dealing with SIM data.
@@ -150,6 +153,9 @@
      */
     public static String
     adnStringFieldToString(byte[] data, int offset, int length) {
+        if (length == 0) {
+            return "";
+        }
         if (length >= 1) {
             if (data[offset] == (byte) 0x80) {
                 int ucslen = (length - 1) / 2;
@@ -225,7 +231,15 @@
             return ret.toString();
         }
 
-        return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length);
+        Resources resource = Resources.getSystem();
+        String defaultCharset = "";
+        try {
+            defaultCharset =
+                    resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset);
+        } catch (NotFoundException e) {
+            // Ignore Exception and defaultCharset is set to a empty string.
+        }
+        return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
     }
 
     static int
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 885e5bc..f6887eb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1150,10 +1150,8 @@
             // No try for permanent failure
             if (cause.isPermanentFail()) {
                 notifyNoData(cause);
-                if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
-                    notifyDataConnection(Phone.REASON_APN_FAILED);
-                    onEnableApn(apnTypeToId(mRequestedApnType), DISABLED);
-                }
+                notifyDataConnection(Phone.REASON_APN_FAILED);
+                onEnableApn(apnTypeToId(mRequestedApnType), DISABLED);
                 return;
             }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index a77484a..e24613f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -33,6 +33,7 @@
 import static android.telephony.SmsMessage.ENCODING_7BIT;
 import static android.telephony.SmsMessage.ENCODING_8BIT;
 import static android.telephony.SmsMessage.ENCODING_16BIT;
+import static android.telephony.SmsMessage.ENCODING_KSC5601;
 import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
 import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
 import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
@@ -776,6 +777,27 @@
             return ret;
         }
 
+        /**
+         * Interprets the user data payload as KSC-5601 characters, and
+         * decodes them into a String.
+         *
+         * @param byteCount the number of bytes in the user data payload
+         * @return a String with the decoded characters
+         */
+        String getUserDataKSC5601(int byteCount) {
+            String ret;
+
+            try {
+                ret = new String(pdu, cur, byteCount, "KSC5601");
+            } catch (UnsupportedEncodingException ex) {
+                ret = "";
+                Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
+            }
+
+            cur += byteCount;
+            return ret;
+        }
+
         boolean moreDataPresent() {
             return (pdu.length > cur);
         }
@@ -1111,6 +1133,16 @@
                 Log.w(LOG_TAG, "MWI for fax, email, or other "
                         + (dataCodingScheme & 0xff));
             }
+        } else if ((dataCodingScheme & 0xC0) == 0x80) {
+            // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
+            // 0x80..0xBF == Reserved coding groups
+            if (dataCodingScheme == 0x84) {
+                // This value used for KSC5601 by carriers in Korea.
+                encodingType = ENCODING_KSC5601;
+            } else {
+                Log.w(LOG_TAG, "5 - Unsupported SMS data coding scheme "
+                        + (dataCodingScheme & 0xff));
+            }
         } else {
             Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
                     + (dataCodingScheme & 0xff));
@@ -1135,6 +1167,10 @@
         case ENCODING_16BIT:
             messageBody = p.getUserDataUCS2(count);
             break;
+
+        case ENCODING_KSC5601:
+            messageBody = p.getUserDataKSC5601(count);
+            break;
         }
 
         if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index b4efeea..f30e11e 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -23,6 +23,7 @@
 import android.net.rtp.AudioGroup;
 import android.net.rtp.AudioStream;
 import android.net.sip.SipAudioCall;
+import android.net.sip.SipErrorCode;
 import android.net.sip.SipManager;
 import android.net.sip.SipProfile;
 import android.net.sip.SipSessionState;
@@ -636,16 +637,15 @@
             }
 
             @Override
-            protected void onError(String errorMessage) {
-                Log.w(LOG_TAG, "SIP error: " + errorMessage);
+            protected void onError(DisconnectCause cause) {
+                Log.w(LOG_TAG, "SIP error: " + cause);
                 if (mSipAudioCall.isInCall()) {
                     // Don't end the call when in call.
                     // TODO: how to deliver the error to PhoneApp
                     return;
                 }
 
-                // FIXME: specify error
-                onCallEnded(DisconnectCause.ERROR_UNSPECIFIED);
+                onCallEnded(cause);
             }
         };
 
@@ -806,7 +806,7 @@
 
     private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter {
         protected abstract void onCallEnded(Connection.DisconnectCause cause);
-        protected abstract void onError(String errorMessage);
+        protected abstract void onError(Connection.DisconnectCause cause);
 
         @Override
         public void onCallEnded(SipAudioCall call) {
@@ -819,8 +819,24 @@
         }
 
         @Override
-        public void onError(SipAudioCall call, String errorMessage) {
-            onError(errorMessage);
+        public void onError(SipAudioCall call, String errorCode,
+                String errorMessage) {
+            switch (Enum.valueOf(SipErrorCode.class, errorCode)) {
+                case INVALID_REMOTE_URI:
+                    onError(Connection.DisconnectCause.INVALID_NUMBER);
+                    break;
+                case TIME_OUT:
+                    onError(Connection.DisconnectCause.CONGESTION);
+                    break;
+                case INVALID_CREDENTIALS:
+                    onError(Connection.DisconnectCause.INVALID_CREDENTIALS);
+                    break;
+                case SOCKET_ERROR:
+                case SERVER_ERROR:
+                case CLIENT_ERROR:
+                default:
+                    onError(Connection.DisconnectCause.ERROR_UNSPECIFIED);
+            }
         }
     }
 }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
index a6b9a2a..7011aeb 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.GsmAlphabet;
+
 import junit.framework.TestCase;
 
 import android.test.suitebuilder.annotation.LargeTest;
@@ -307,4 +309,26 @@
         assertEquals("a",
                 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
     }
+
+    @SmallTest
+    public void testGsm8BitUpackedWithEuckr() throws Exception {
+        // Some feature phones in Korea store contacts as euc-kr.
+        // Test this situations.
+        byte unpacked[];
+
+        // Test general alphabet strings.
+        unpacked = IccUtils.hexStringToBytes("61626320646566FF");
+        assertEquals("abc def",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr"));
+
+        // Test korean strings.
+        unpacked = IccUtils.hexStringToBytes("C5D7BDBAC6AEFF");
+        assertEquals("\uD14C\uC2A4\uD2B8",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr"));
+
+        // Test gsm Extented Characters.
+        unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars);
+        assertEquals(sGsmExtendedChars,
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr"));
+    }
 }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java
index db38ede..ef62d85 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java
@@ -28,7 +28,7 @@
     public void testBasic() throws Exception {
         byte[] data, data2;
 
-        /* 
+        /*
          * bcdToString()
          */
 
@@ -40,9 +40,13 @@
         assertEquals("0126045001448486", IccUtils.bcdToString(data, 1, data.length - 2));
 
         // Stops on invalid BCD value
-        data = IccUtils.hexStringToBytes("98F062400510444868f2");
+        data = IccUtils.hexStringToBytes("98E062400510444868f2");
         assertEquals("890", IccUtils.bcdToString(data, 0, data.length));
 
+        // skip the high nibble 'F' since some PLMNs have it
+        data = IccUtils.hexStringToBytes("98F062400510444868f2");
+        assertEquals("890260450014484862", IccUtils.bcdToString(data, 0, data.length));
+
         /*
          * gsmBcdByteToInt()
          */
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index db1e5ef..ec1cbf1 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -230,6 +230,16 @@
         </activity>
 
         <activity
+                android:name="FramebufferBlendActivity"
+                android:label="_FramebufferBlend">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+
+        <activity
                 android:name="StackActivity"
                 android:label="_Stacks">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/FramebufferBlendActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/FramebufferBlendActivity.java
new file mode 100644
index 0000000..ef84b67
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/FramebufferBlendActivity.java
@@ -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.
+ */
+
+
+package com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class FramebufferBlendActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(new BlendView(this));
+    }
+
+    static class BlendView extends View {
+        private int mTexWidth;
+        private int mTexHeight;
+        private Paint mPaint;
+        private LinearGradient mHorGradient;
+        private Bitmap mTexture;
+
+        BlendView(Context c) {
+            super(c);
+
+            mTexture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+            mTexWidth = mTexture.getWidth();
+            mTexHeight = mTexture.getHeight();
+
+            mHorGradient = new LinearGradient(0.0f, 0.0f, mTexWidth, 0.0f,
+                    Color.BLACK, Color.WHITE, Shader.TileMode.CLAMP);
+
+            mPaint = new Paint();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRGB(255, 255, 255);
+
+            canvas.save();
+            canvas.translate(40.0f, 40.0f);
+
+            drawBlendedBitmap(canvas, PorterDuff.Mode.DARKEN);
+            drawBlendedBitmap(canvas, PorterDuff.Mode.LIGHTEN);
+            drawBlendedBitmap(canvas, PorterDuff.Mode.MULTIPLY);
+
+            canvas.restore();
+
+            canvas.save();
+            canvas.translate(40.0f + mTexWidth + 40.0f, 40.0f);
+
+            drawBlendedBitmap(canvas, PorterDuff.Mode.SCREEN);
+            drawBlendedBitmap(canvas, PorterDuff.Mode.ADD);
+            drawBlendedBitmapInverse(canvas, PorterDuff.Mode.OVERLAY);
+
+            canvas.restore();
+        }
+
+        private void drawBlendedBitmap(Canvas canvas, PorterDuff.Mode mode) {
+            mPaint.setShader(null);
+            mPaint.setXfermode(null);
+            canvas.drawBitmap(mTexture, 0.0f, 0.0f, mPaint);
+
+            mPaint.setShader(mHorGradient);
+            mPaint.setXfermode(new PorterDuffXfermode(mode));
+            canvas.drawRect(0.0f, 0.0f, mTexWidth, mTexHeight, mPaint);
+
+            canvas.translate(0.0f, 40.0f + mTexHeight);
+        }
+
+        private void drawBlendedBitmapInverse(Canvas canvas, PorterDuff.Mode mode) {
+            mPaint.setXfermode(null);
+            mPaint.setShader(mHorGradient);
+            canvas.drawRect(0.0f, 0.0f, mTexWidth, mTexHeight, mPaint);
+
+            mPaint.setXfermode(new PorterDuffXfermode(mode));
+            mPaint.setShader(null);
+            canvas.drawBitmap(mTexture, 0.0f, 0.0f, mPaint);
+
+            canvas.translate(0.0f, 40.0f + mTexHeight);
+        }
+    }
+}
diff --git a/voip/java/android/net/sip/ISipSessionListener.aidl b/voip/java/android/net/sip/ISipSessionListener.aidl
index c552a57..0a6220b 100644
--- a/voip/java/android/net/sip/ISipSessionListener.aidl
+++ b/voip/java/android/net/sip/ISipSessionListener.aidl
@@ -76,20 +76,20 @@
      * termination.
      *
      * @param session the session object that carries out the transaction
-     * @param errorClass name of the exception class
+     * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onError(in ISipSession session, String errorClass,
+    void onError(in ISipSession session, String errorCode,
             String errorMessage);
 
     /**
      * Called when an error occurs during session modification negotiation.
      *
      * @param session the session object that carries out the transaction
-     * @param errorClass name of the exception class
+     * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onCallChangeFailed(in ISipSession session, String errorClass,
+    void onCallChangeFailed(in ISipSession session, String errorCode,
             String errorMessage);
 
     /**
@@ -111,10 +111,10 @@
      * Called when the registration fails.
      *
      * @param session the session object that carries out the transaction
-     * @param errorClass name of the exception class
+     * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onRegistrationFailed(in ISipSession session, String errorClass,
+    void onRegistrationFailed(in ISipSession session, String errorCode,
             String errorMessage);
 
     /**
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index 8254543..02f82b3 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -90,9 +90,10 @@
          * Called when an error occurs.
          *
          * @param call the call object that carries out the audio call
+         * @param errorCode error code defined in {@link SipErrorCode}
          * @param errorMessage error message
          */
-        void onError(SipAudioCall call, String errorMessage);
+        void onError(SipAudioCall call, String errorCode, String errorMessage);
     }
 
     /**
@@ -126,7 +127,8 @@
         public void onCallHeld(SipAudioCall call) {
             onChanged(call);
         }
-        public void onError(SipAudioCall call, String errorMessage) {
+        public void onError(SipAudioCall call, String errorCode,
+                String errorMessage) {
             onChanged(call);
         }
     }
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index bd2c1cd..a4fa053 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -104,7 +104,8 @@
                 listener.onCalling(this);
                 break;
             default:
-                listener.onError(this, "wrong state to attach call: " + state);
+                listener.onError(this, SipErrorCode.CLIENT_ERROR.toString(),
+                        "wrong state to attach call: " + state);
             }
         } catch (Throwable t) {
             Log.e(TAG, "setListener()", t);
@@ -271,14 +272,13 @@
     }
 
     @Override
-    public void onCallChangeFailed(ISipSession session,
-            String className, String message) {
+    public void onCallChangeFailed(ISipSession session, String errorCode,
+            String message) {
         Log.d(TAG, "sip call change failed: " + message);
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onError(SipAudioCallImpl.this,
-                        className + ": " + message);
+                listener.onError(SipAudioCallImpl.this, errorCode, message);
             } catch (Throwable t) {
                 Log.e(TAG, "onCallBusy()", t);
             }
@@ -286,17 +286,16 @@
     }
 
     @Override
-    public void onError(ISipSession session, String className,
+    public void onError(ISipSession session, String errorCode,
             String message) {
-        Log.d(TAG, "sip session error: " + className + ": " + message);
+        Log.d(TAG, "sip session error: " + errorCode + ": " + message);
         synchronized (this) {
             if (!isInCall()) close(true);
         }
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onError(SipAudioCallImpl.this,
-                        className + ": " + message);
+                listener.onError(SipAudioCallImpl.this, errorCode, message);
             } catch (Throwable t) {
                 Log.e(TAG, "onError()", t);
             }
diff --git a/voip/java/android/net/sip/SipErrorCode.java b/voip/java/android/net/sip/SipErrorCode.java
new file mode 100644
index 0000000..2eb67e8
--- /dev/null
+++ b/voip/java/android/net/sip/SipErrorCode.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.sip;
+
+/**
+ * Defines error code returned in
+ * {@link SipRegistrationListener#onRegistrationFailed(String, String, String)},
+ * {@link ISipSessionListener#onError(ISipSession, String, String)},
+ * {@link ISipSessionListener#onCallChangeFailed(ISipSession, String, String)} and
+ * {@link ISipSessionListener#onRegistrationFailed(ISipSession, String, String)}.
+ * @hide
+ */
+public enum SipErrorCode {
+    /** When some socket error occurs. */
+    SOCKET_ERROR,
+
+    /** When server responds with an error. */
+    SERVER_ERROR,
+
+    /** When some error occurs on the device, possibly due to a bug. */
+    CLIENT_ERROR,
+
+    /** When the transaction gets timed out. */
+    TIME_OUT,
+
+    /** When the remote URI is not valid. */
+    INVALID_REMOTE_URI,
+
+    /** When invalid credentials are provided. */
+    INVALID_CREDENTIALS;
+}
diff --git a/voip/java/android/net/sip/SipRegistrationListener.java b/voip/java/android/net/sip/SipRegistrationListener.java
index 63faaf8..22488d7 100644
--- a/voip/java/android/net/sip/SipRegistrationListener.java
+++ b/voip/java/android/net/sip/SipRegistrationListener.java
@@ -40,9 +40,9 @@
      * Called when the registration fails.
      *
      * @param localProfileUri the URI string of the SIP profile to register with
-     * @param errorClass name of the exception class
+     * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onRegistrationFailed(String localProfileUri, String errorClass,
+    void onRegistrationFailed(String localProfileUri, String errorCode,
             String errorMessage);
 }
diff --git a/voip/java/android/net/sip/SipSessionAdapter.java b/voip/java/android/net/sip/SipSessionAdapter.java
index 770d4eb..6020f2c 100644
--- a/voip/java/android/net/sip/SipSessionAdapter.java
+++ b/voip/java/android/net/sip/SipSessionAdapter.java
@@ -42,14 +42,11 @@
     public void onCallBusy(ISipSession session) {
     }
 
-    public void onCallChanged(ISipSession session, byte[] sessionDescription) {
-    }
-
-    public void onCallChangeFailed(ISipSession session, String className,
+    public void onCallChangeFailed(ISipSession session, String errorCode,
             String message) {
     }
 
-    public void onError(ISipSession session, String className, String message) {
+    public void onError(ISipSession session, String errorCode, String message) {
     }
 
     public void onRegistering(ISipSession session) {
@@ -58,7 +55,7 @@
     public void onRegistrationDone(ISipSession session, int duration) {
     }
 
-    public void onRegistrationFailed(ISipSession session, String className,
+    public void onRegistrationFailed(ISipSession session, String errorCode,
             String message) {
     }