Merge "MTP: Add support for host cancellation of file transfers."
diff --git a/Android.mk b/Android.mk
index b839f57..2ce4c00 100644
--- a/Android.mk
+++ b/Android.mk
@@ -86,7 +86,6 @@
 	core/java/android/app/ISearchManager.aidl \
 	core/java/android/app/ISearchManagerCallback.aidl \
 	core/java/android/app/IServiceConnection.aidl \
-	core/java/android/app/IStatusBar.aidl \
 	core/java/android/app/IThumbnailReceiver.aidl \
 	core/java/android/app/ITransientNotification.aidl \
 	core/java/android/app/IUiModeManager.aidl \
@@ -155,6 +154,8 @@
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
+	core/java/com/android/internal/statusbar/IStatusBar.aidl \
+	core/java/com/android/internal/statusbar/IStatusBarService.aidl \
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
 	core/java/com/android/internal/view/IInputMethod.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6455103..26d8a1b 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -53,6 +53,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FrameworkTest_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.policy*)
 $(call add-clean-step, rm -rf $(TARGET_OUT_JAVA_LIBRARIES)/android.policy.jar)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 
 
 # ************************************************
diff --git a/api/9.xml b/api/9.xml
index 1d6f647..20397df 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -289751,7 +289751,7 @@
  extends="java.lang.Object"
  abstract="false"
  static="false"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
diff --git a/api/current.xml b/api/current.xml
index a01ed51..d79fab6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4563,6 +4563,17 @@
  visibility="public"
 >
 </field>
+<field name="hardwareAccelerated"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843540"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="hasCode"
  type="int"
  transient="false"
@@ -28074,6 +28085,17 @@
 <parameter name="parcel" type="android.os.Parcel">
 </parameter>
 </constructor>
+<method name="clone"
+ return="android.app.Notification"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -39439,6 +39461,25 @@
 <parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
 </parameter>
 </method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
 <method name="peekWallpaper"
  return="android.graphics.drawable.Drawable"
  abstract="true"
@@ -40866,6 +40907,25 @@
 <parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
 </parameter>
 </method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
 <method name="peekWallpaper"
  return="android.graphics.drawable.Drawable"
  abstract="false"
@@ -48600,6 +48660,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_HARDWARE_ACCELERATED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_HAS_CODE"
  type="int"
  transient="false"
@@ -55636,6 +55707,19 @@
 <parameter name="column" type="int">
 </parameter>
 </method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="column" type="int">
+</parameter>
+</method>
 <method name="getUpdatedField"
  return="java.lang.Object"
  abstract="false"
@@ -56659,6 +56743,19 @@
 <parameter name="columnIndex" type="int">
 </parameter>
 </method>
+<method name="getType"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
 <method name="getWantsAllOnMoveCalls"
  return="boolean"
  abstract="true"
@@ -56899,6 +56996,61 @@
 <parameter name="observer" type="android.database.DataSetObserver">
 </parameter>
 </method>
+<field name="FIELD_TYPE_BLOB"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_FLOAT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_INTEGER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_NULL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_STRING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </interface>
 <class name="CursorIndexOutOfBoundsException"
  extends="java.lang.IndexOutOfBoundsException"
@@ -57256,6 +57408,21 @@
 <parameter name="col" type="int">
 </parameter>
 </method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
 <method name="isBlob"
  return="boolean"
  abstract="false"
@@ -57263,7 +57430,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="row" type="int">
@@ -57278,7 +57445,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="row" type="int">
@@ -57293,7 +57460,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="row" type="int">
@@ -57308,7 +57475,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="row" type="int">
@@ -57323,7 +57490,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="row" type="int">
@@ -57734,6 +57901,19 @@
 <parameter name="columnIndex" type="int">
 </parameter>
 </method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
 <method name="getWantsAllOnMoveCalls"
  return="boolean"
  abstract="false"
@@ -60887,6 +61067,24 @@
 <parameter name="version" type="int">
 </parameter>
 </constructor>
+<constructor name="SQLiteOpenHelper"
+ type="android.database.sqlite.SQLiteOpenHelper"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="version" type="int">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</constructor>
 <method name="close"
  return="void"
  abstract="false"
@@ -154969,6 +155167,25 @@
 <parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
 </parameter>
 </method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="file" type="java.lang.String">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
 <method name="peekWallpaper"
  return="android.graphics.drawable.Drawable"
  abstract="false"
@@ -155535,6 +155752,19 @@
 <parameter name="columnIndex" type="int">
 </parameter>
 </method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
 <method name="getWantsAllOnMoveCalls"
  return="boolean"
  abstract="false"
@@ -201419,6 +201649,28 @@
  visibility="public"
 >
 </method>
+<method name="canZoomIn"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canZoomOut"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="capturePicture"
  return="android.graphics.Picture"
  abstract="false"
@@ -214371,6 +214623,17 @@
 <parameter name="parent" type="android.view.ViewGroup">
 </parameter>
 </method>
+<method name="clone"
+ return="android.widget.RemoteViews"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -225041,6 +225304,46 @@
  visibility="public"
 >
 </field>
+<field name="KERNING"
+ type="java.awt.font.TextAttribute"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KERNING_ON"
+ type="java.lang.Integer"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LIGATURES"
+ type="java.awt.font.TextAttribute"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LIGATURES_ON"
+ type="java.lang.Integer"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NUMERIC_SHAPING"
  type="java.awt.font.TextAttribute"
  transient="false"
@@ -225191,6 +225494,36 @@
  visibility="public"
 >
 </field>
+<field name="TRACKING"
+ type="java.awt.font.TextAttribute"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRACKING_LOOSE"
+ type="java.lang.Float"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRACKING_TIGHT"
+ type="java.lang.Float"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TRANSFORM"
  type="java.awt.font.TextAttribute"
  transient="false"
@@ -270596,7 +270929,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="repl" type="byte[]">
+<parameter name="replacement" type="byte[]">
 </parameter>
 </method>
 <method name="malformedInputAction"
@@ -296747,6 +297080,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<implements name="java.lang.Iterable">
+</implements>
 <implements name="java.io.Serializable">
 </implements>
 <constructor name="SQLException"
@@ -303750,7 +304085,7 @@
  extends="java.lang.Object"
  abstract="false"
  static="false"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -303881,7 +304216,7 @@
  native="false"
  synchronized="false"
  static="true"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -303892,7 +304227,7 @@
  native="false"
  synchronized="false"
  static="true"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -314143,6 +314478,8 @@
 >
 <implements name="java.lang.Cloneable">
 </implements>
+<implements name="java.util.Deque">
+</implements>
 <implements name="java.util.List">
 </implements>
 <implements name="java.util.Queue">
@@ -322471,317 +322808,6 @@
 </parameter>
 </method>
 </class>
-<class name="ConcurrentLinkedDeque"
- extends="java.util.AbstractCollection"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="java.util.Deque">
-</implements>
-<implements name="java.io.Serializable">
-</implements>
-<constructor name="ConcurrentLinkedDeque"
- type="java.util.concurrent.ConcurrentLinkedDeque"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="ConcurrentLinkedDeque"
- type="java.util.concurrent.ConcurrentLinkedDeque"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="c" type="java.util.Collection&lt;? extends E&gt;">
-</parameter>
-</constructor>
-<method name="addFirst"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="e" type="E">
-</parameter>
-</method>
-<method name="addLast"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="e" type="E">
-</parameter>
-</method>
-<method name="descendingIterator"
- return="java.util.Iterator&lt;E&gt;"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="element"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getFirst"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getLast"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="iterator"
- return="java.util.Iterator&lt;E&gt;"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="offer"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="e" type="E">
-</parameter>
-</method>
-<method name="offerFirst"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="e" type="E">
-</parameter>
-</method>
-<method name="offerLast"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="e" type="E">
-</parameter>
-</method>
-<method name="peek"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="peekFirst"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="peekLast"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="poll"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="pollFirst"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="pollLast"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="pop"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="push"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="e" type="E">
-</parameter>
-</method>
-<method name="remove"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="removeFirst"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="removeFirstOccurrence"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="o" type="java.lang.Object">
-</parameter>
-</method>
-<method name="removeLast"
- return="E"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="removeLastOccurrence"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="o" type="java.lang.Object">
-</parameter>
-</method>
-<method name="size"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
 <class name="ConcurrentLinkedQueue"
  extends="java.util.AbstractQueue"
  abstract="false"
@@ -338972,7 +338998,7 @@
  visibility="protected"
 >
 </field>
-<field name="deflater"
+<field name="def"
  type="java.util.zip.Deflater"
  transient="false"
  volatile="false"
@@ -339455,7 +339481,7 @@
 >
 <parameter name="is" type="java.io.InputStream">
 </parameter>
-<parameter name="inf" type="java.util.zip.Inflater">
+<parameter name="inflater" type="java.util.zip.Inflater">
 </parameter>
 </constructor>
 <constructor name="InflaterInputStream"
@@ -339467,7 +339493,7 @@
 >
 <parameter name="is" type="java.io.InputStream">
 </parameter>
-<parameter name="inf" type="java.util.zip.Inflater">
+<parameter name="inflater" type="java.util.zip.Inflater">
 </parameter>
 <parameter name="bsize" type="int">
 </parameter>
@@ -339544,7 +339570,7 @@
 >
 <parameter name="out" type="java.io.OutputStream">
 </parameter>
-<parameter name="inflater" type="java.util.zip.Inflater">
+<parameter name="inf" type="java.util.zip.Inflater">
 </parameter>
 </constructor>
 <constructor name="InflaterOutputStream"
@@ -339556,7 +339582,7 @@
 >
 <parameter name="out" type="java.io.OutputStream">
 </parameter>
-<parameter name="inflater" type="java.util.zip.Inflater">
+<parameter name="inf" type="java.util.zip.Inflater">
 </parameter>
 <parameter name="bufferSize" type="int">
 </parameter>
@@ -339585,7 +339611,7 @@
  visibility="protected"
 >
 </field>
-<field name="inflater"
+<field name="inf"
  type="java.util.zip.Inflater"
  transient="false"
  volatile="false"
@@ -356571,7 +356597,7 @@
 </method>
 <method name="engineGetDefaultSSLParameters"
  return="javax.net.ssl.SSLParameters"
- abstract="true"
+ abstract="false"
  native="false"
  synchronized="false"
  static="false"
@@ -356615,7 +356641,7 @@
 </method>
 <method name="engineGetSupportedSSLParameters"
  return="javax.net.ssl.SSLParameters"
- abstract="true"
+ abstract="false"
  native="false"
  synchronized="false"
  static="false"
@@ -359692,6 +359718,18 @@
 <parameter name="name" type="java.lang.String">
 </parameter>
 </constructor>
+<constructor name="X500Principal"
+ type="javax.security.auth.x500.X500Principal"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="keywordMap" type="java.util.Map&lt;java.lang.String, java.lang.String&gt;">
+</parameter>
+</constructor>
 <method name="getEncoded"
  return="byte[]"
  abstract="false"
@@ -359727,6 +359765,21 @@
 <parameter name="format" type="java.lang.String">
 </parameter>
 </method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="oidMap" type="java.util.Map&lt;java.lang.String, java.lang.String&gt;">
+</parameter>
+</method>
 <field name="CANONICAL"
  type="java.lang.String"
  transient="false"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index ac2eb0d..7a7f8ed 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -38,7 +38,7 @@
 #include <ui/EGLUtils.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 
 #include <core/SkBitmap.h>
 #include <images/SkImageDecoder.h>
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5217f5e..1be05b2 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -57,6 +57,7 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
@@ -543,6 +544,15 @@
     }
 
     @Override
+    public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
+            DatabaseErrorHandler errorHandler) {
+        File f = validateFilePath(name, true);
+        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler);
+        setFilePermissionsFromMode(f.getPath(), mode, 0);
+        return db;
+    }
+
+    @Override
     public boolean deleteDatabase(String name) {
         try {
             File f = validateFilePath(name, false);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 0235599..da8c9e5 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -138,7 +138,7 @@
     public Dialog(Context context, int theme) {
         mContext = new ContextThemeWrapper(
             context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);
-        mWindowManager = (WindowManager)context.getSystemService("window");
+        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
         Window w = PolicyManager.makeNewWindow(mContext);
         mWindow = w;
         w.setCallback(this);
diff --git a/core/java/android/app/IStatusBar.aidl b/core/java/android/app/IStatusBar.aidl
deleted file mode 100644
index c64fa50..0000000
--- a/core/java/android/app/IStatusBar.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
- 
-package android.app;
-
-/** @hide */
-interface IStatusBar
-{
-    void activate();
-    void deactivate();
-    void toggle();
-    void disable(int what, IBinder token, String pkg);
-    IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel);
-    void updateIcon(IBinder key, String slot, String iconPackage, int iconId, int iconLevel);
-    void removeIcon(IBinder key);
-}
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 84a57b52..4bf5518 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -18,9 +18,7 @@
 
 import android.os.Bundle;
 import android.os.Handler;
-import android.view.KeyEvent;
 import android.view.View;
-import android.widget.Adapter;
 import android.widget.AdapterView;
 import android.widget.ListAdapter;
 import android.widget.ListView;
@@ -68,7 +66,7 @@
  *               android:layout_weight=&quot;1&quot;
  *               android:drawSelectorOnTop=&quot;false&quot;/&gt;
  *
- *     &lt;TextView id=&quot;@id/android:empty&quot;
+ *     &lt;TextView android:id=&quot;@id/android:empty&quot;
  *               android:layout_width=&quot;match_parent&quot;
  *               android:layout_height=&quot;match_parent&quot;
  *               android:background=&quot;#FF0000&quot;
@@ -316,7 +314,7 @@
     }
 
     private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
-        public void onItemClick(AdapterView parent, View v, int position, long id)
+        public void onItemClick(AdapterView<?> parent, View v, int position, long id)
         {
             onListItemClick((ListView)parent, v, position, id);
         }
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index be8f413..524de6f 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -20,13 +20,11 @@
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
 import android.os.Bundle;
-import android.util.Config;
 import android.util.Log;
 import android.view.Window;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 /**
@@ -38,7 +36,7 @@
  */
 public class LocalActivityManager {
     private static final String TAG = "LocalActivityManager";
-    private static final boolean localLOGV = false || Config.LOGV;
+    private static final boolean localLOGV = false;
 
     // Internal token for an Activity being managed by LocalActivityManager.
     private static class LocalActivityRecord extends Binder {
@@ -351,7 +349,7 @@
     }
 
     private Window performDestroy(LocalActivityRecord r, boolean finish) {
-        Window win = null;
+        Window win;
         win = r.window;
         if (r.curState == RESUMED && !finish) {
             performPause(r, finish);
@@ -385,7 +383,8 @@
         if (r != null) {
             win = performDestroy(r, finish);
             if (finish) {
-                mActivities.remove(r);
+                mActivities.remove(id);
+                mActivityArray.remove(r);
             }
         }
         return win;
@@ -446,10 +445,8 @@
      */
     public void dispatchCreate(Bundle state) {
         if (state != null) {
-            final Iterator<String> i = state.keySet().iterator();
-            while (i.hasNext()) {
+            for (String id : state.keySet()) {
                 try {
-                    final String id = i.next();
                     final Bundle astate = state.getBundle(id);
                     LocalActivityRecord r = mActivities.get(id);
                     if (r != null) {
@@ -462,9 +459,7 @@
                     }
                 } catch (Exception e) {
                     // Recover from -all- app errors.
-                    Log.e(TAG,
-                          "Exception thrown when restoring LocalActivityManager state",
-                          e);
+                    Log.e(TAG, "Exception thrown when restoring LocalActivityManager state", e);
                 }
             }
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4d72f73..739aca3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -341,6 +341,44 @@
         iconLevel = parcel.readInt();
     }
 
+    public Notification clone() {
+        Notification that = new Notification();
+
+        that.when = this.when;
+        that.icon = this.icon;
+        that.number = this.number;
+
+        // PendingIntents are global, so there's no reason (or way) to clone them.
+        that.contentIntent = this.contentIntent;
+        that.deleteIntent = this.deleteIntent;
+
+        if (this.tickerText != null) {
+            that.tickerText = this.tickerText.toString();
+        }
+        if (this.contentView != null) {
+            that.contentView = this.contentView.clone();
+        }
+        that.iconLevel = that.iconLevel;
+        that.sound = this.sound; // android.net.Uri is immutable
+        that.audioStreamType = this.audioStreamType;
+
+        final long[] vibrate = this.vibrate;
+        if (vibrate != null) {
+            final int N = vibrate.length;
+            final long[] vib = that.vibrate = new long[N];
+            System.arraycopy(vibrate, 0, vib, 0, N);
+        }
+
+        that.ledARGB = this.ledARGB;
+        that.ledOnMS = this.ledOnMS;
+        that.ledOffMS = this.ledOffMS;
+        that.defaults = this.defaults;
+        
+        that.flags = this.flags;
+
+        return that;
+    }
+
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 72ec616..de544fb 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -23,6 +23,8 @@
 import android.os.IBinder;
 import android.os.ServiceManager;
 
+import com.android.internal.statusbar.IStatusBarService;
+
 /**
  * Allows an app to control the status bar.
  *
@@ -58,12 +60,12 @@
     public static final int DISABLE_NONE = 0x00000000;
 
     private Context mContext;
-    private IStatusBar mService;
+    private IStatusBarService mService;
     private IBinder mToken = new Binder();
 
     StatusBarManager(Context context) {
         mContext = context;
-        mService = IStatusBar.Stub.asInterface(
+        mService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
     }
 
@@ -85,7 +87,7 @@
      */
     public void expand() {
         try {
-            mService.activate();
+            mService.expand();
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
@@ -97,46 +99,34 @@
      */
     public void collapse() {
         try {
-            mService.deactivate();
-        } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
-        }
-    }
-    
-    /**
-     * Toggle the status bar.
-     */
-    public void toggle() {
-        try {
-            mService.toggle();
+            mService.collapse();
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
         }
     }
 
-    public IBinder addIcon(String slot, int iconId, int iconLevel) {
+    public void setIcon(String slot, int iconId, int iconLevel) {
         try {
-            return mService.addIcon(slot, mContext.getPackageName(), iconId, iconLevel);
+            mService.setIcon(slot, mContext.getPackageName(), iconId, iconLevel);
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
         }
     }
 
-    public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) {
+    public void removeIcon(String slot) {
         try {
-            mService.updateIcon(key, slot, mContext.getPackageName(), iconId, iconLevel);
+            mService.removeIcon(slot);
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
         }
     }
 
-    public void removeIcon(IBinder key) {
+    public void setIconVisibility(String slot, boolean visible) {
         try {
-            mService.removeIcon(key);
+            mService.setIconVisibility(slot, visible);
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0afd6d2..86ddee4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -21,6 +21,7 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
@@ -588,6 +589,32 @@
             int mode, CursorFactory factory);
 
     /**
+     * Open a new private SQLiteDatabase associated with this Context's
+     * application package.  Creates the database file if it doesn't exist.
+     *
+     * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
+     * used to handle corruption when sqlite reports database corruption.</p>
+     *
+     * @param name The name (unique in the application package) of the database.
+     * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
+     *     default operation, {@link #MODE_WORLD_READABLE}
+     *     and {@link #MODE_WORLD_WRITEABLE} to control permissions.
+     * @param factory An optional factory class that is called to instantiate a
+     *     cursor when query is called.
+     * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
+     * corruption. if null, {@link android.database.DefaultDatabaseErrorHandler} is assumed.
+     * @return The contents of a newly created database with the given name.
+     * @throws android.database.sqlite.SQLiteException if the database file could not be opened.
+     *
+     * @see #MODE_PRIVATE
+     * @see #MODE_WORLD_READABLE
+     * @see #MODE_WORLD_WRITEABLE
+     * @see #deleteDatabase
+     */
+    public abstract SQLiteDatabase openOrCreateDatabase(String name,
+            int mode, CursorFactory factory, DatabaseErrorHandler errorHandler);
+
+    /**
      * Delete an existing private SQLiteDatabase associated with this Context's
      * application package.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a447108..3f5d215 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
@@ -204,6 +205,12 @@
     }
 
     @Override
+    public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
+            DatabaseErrorHandler errorHandler) {
+        return mBase.openOrCreateDatabase(name, mode, factory, errorHandler);
+    }
+
+    @Override
     public boolean deleteDatabase(String name) {
         return mBase.deleteDatabase(name);
     }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7047113..27eeb69 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -273,6 +273,12 @@
     public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
     
     /**
+     * Value for {@link #flags}: true when the application's rendering should
+     * be hardware accelerated.
+     */
+    public static final int FLAG_HARDWARE_ACCELERATED = 1<<20;
+    
+    /**
      * Value for {@link #flags}: this is true if the application has set
      * its android:neverEncrypt to true, false otherwise. It is used to specify
      * that this package specifically "opts-out" of a secured file system solution,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4ddc124..1b657f6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1536,6 +1536,12 @@
         }
 
         if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
+                false)) {
+            ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
+        }
+
+        if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
                 true)) {
             ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 6170bae..b1f33ec 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -51,6 +51,10 @@
     abstract public double getDouble(int column);
     abstract public boolean isNull(int column);
 
+    public int getType(int column) {
+        throw new UnsupportedOperationException();
+    }
+
     // TODO implement getBlob in all cursor types
     public byte[] getBlob(int column) {
         throw new UnsupportedOperationException("getBlob is not supported");
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 27a02e2..e47d9ce 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -149,63 +149,36 @@
             }
         }
 
-        return mWindow.isNull(mPos, columnIndex);
+        return mWindow.getType(mPos, columnIndex) == Cursor.FIELD_TYPE_NULL;
     }
 
-    public boolean isBlob(int columnIndex)
+    public boolean isBlob(int columnIndex) {
+        return getType(columnIndex) == Cursor.FIELD_TYPE_BLOB;
+    }
+
+    public boolean isString(int columnIndex) {
+        return getType(columnIndex) == Cursor.FIELD_TYPE_STRING;
+    }
+
+    public boolean isLong(int columnIndex) {
+        return getType(columnIndex) == Cursor.FIELD_TYPE_INTEGER;
+    }
+
+    public boolean isFloat(int columnIndex) {
+        return getType(columnIndex) == Cursor.FIELD_TYPE_FLOAT;
+    }
+
+    @Override
+    public int getType(int columnIndex)
     {
         checkPosition();
-
         synchronized(mUpdatedRows) {
             if (isFieldUpdated(columnIndex)) {
-                Object object = getUpdatedField(columnIndex);
-                return object == null || object instanceof byte[];
+                return DatabaseUtils.getTypeOfObject(getUpdatedField(columnIndex));
             }
         }
 
-        return mWindow.isBlob(mPos, columnIndex);
-    }
-
-    public boolean isString(int columnIndex)
-    {
-        checkPosition();
-
-        synchronized(mUpdatedRows) {
-            if (isFieldUpdated(columnIndex)) {
-                Object object = getUpdatedField(columnIndex);
-                return object == null || object instanceof String;
-            }
-        }
-
-        return mWindow.isString(mPos, columnIndex);
-    }
-
-    public boolean isLong(int columnIndex)
-    {
-        checkPosition();
-
-        synchronized(mUpdatedRows) {
-            if (isFieldUpdated(columnIndex)) {
-                Object object = getUpdatedField(columnIndex);
-                return object != null && (object instanceof Integer || object instanceof Long);
-            }
-        }
-
-        return mWindow.isLong(mPos, columnIndex);
-    }
-
-    public boolean isFloat(int columnIndex)
-    {
-        checkPosition();
-
-        synchronized(mUpdatedRows) {
-            if (isFieldUpdated(columnIndex)) {
-                Object object = getUpdatedField(columnIndex);
-                return object != null && (object instanceof Float || object instanceof Double);
-            }
-        }
-
-        return mWindow.isFloat(mPos, columnIndex);
+        return mWindow.getType(mPos, columnIndex);
     }
 
     @Override
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index fee658a..c03c586 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -30,6 +30,25 @@
  * threads should perform its own synchronization when using the Cursor.
  */
 public interface Cursor {
+    /*
+     * Values returned by {@link #getType(int)}.
+     * These should be consistent with the corresponding types defined in CursorWindow.h
+     */
+    /** Value returned by {@link #getType(int)} if the specified column is null */
+    static final int FIELD_TYPE_NULL = 0;
+
+    /** Value returned by {@link #getType(int)} if the specified  column type is integer */
+    static final int FIELD_TYPE_INTEGER = 1;
+
+    /** Value returned by {@link #getType(int)} if the specified column type is float */
+    static final int FIELD_TYPE_FLOAT = 2;
+
+    /** Value returned by {@link #getType(int)} if the specified column type is string */
+    static final int FIELD_TYPE_STRING = 3;
+
+    /** Value returned by {@link #getType(int)} if the specified column type is blob */
+    static final int FIELD_TYPE_BLOB = 4;
+
     /**
      * Returns the numbers of rows in the cursor.
      *
@@ -279,6 +298,27 @@
     double getDouble(int columnIndex);
 
     /**
+     * Returns data type of the given column's value.
+     * The preferred type of the column is returned but the data may be converted to other types
+     * as documented in the get-type methods such as {@link #getInt(int)}, {@link #getFloat(int)}
+     * etc.
+     *<p>
+     * Returned column types are
+     * <ul>
+     *   <li>{@link #FIELD_TYPE_NULL}</li>
+     *   <li>{@link #FIELD_TYPE_INTEGER}</li>
+     *   <li>{@link #FIELD_TYPE_FLOAT}</li>
+     *   <li>{@link #FIELD_TYPE_STRING}</li>
+     *   <li>{@link #FIELD_TYPE_BLOB}</li>
+     *</ul>
+     *</p>
+     *
+     * @param columnIndex the zero-based index of the target column.
+     * @return column value type
+     */
+    int getType(int columnIndex);
+
+    /**
      * Returns <code>true</code> if the value in the indicated column is null.
      *
      * @param columnIndex the zero-based index of the target column.
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index c756825..39889b9 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -217,14 +217,11 @@
      * @param row the row to read from, row - getStartPosition() being the actual row in the window
      * @param col the column to read from
      * @return {@code true} if given field is {@code NULL}
+     * @deprecated use {@link #getType(int, int)} instead
      */
+    @Deprecated
     public boolean isNull(int row, int col) {
-        acquireReference();
-        try {
-            return isNull_native(row - mStartPos, col);
-        } finally {
-            releaseReference();
-        }
+        return getType(row, col) == Cursor.FIELD_TYPE_NULL;
     }
     
     private native boolean isNull_native(int row, int col);
@@ -248,19 +245,42 @@
     private native byte[] getBlob_native(int row, int col);
 
     /**
+     * Returns data type of the given column's value.
+     *<p>
+     * Returned column types are
+     * <ul>
+     *   <li>{@link Cursor#FIELD_TYPE_NULL}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_STRING}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
+     *</ul>
+     *</p>
+     *
+     * @param row the row to read from, row - getStartPosition() being the actual row in the window
+     * @param col the column to read from
+     * @return the value type
+     */
+    public int getType(int row, int col) {
+        acquireReference();
+        try {
+            return getType_native(row - mStartPos, col);
+        } finally {
+            releaseReference();
+        }
+    }
+
+    /**
      * Checks if a field contains either a blob or is null.
      *
      * @param row the row to read from, row - getStartPosition() being the actual row in the window
      * @param col the column to read from
      * @return {@code true} if given field is {@code NULL} or a blob
+     * @deprecated use {@link #getType(int, int)} instead
      */
+    @Deprecated
     public boolean isBlob(int row, int col) {
-        acquireReference();
-        try {
-            return isBlob_native(row - mStartPos, col);
-        } finally {
-            releaseReference();
-        }
+        return getType(row, col) == Cursor.FIELD_TYPE_BLOB;
     }
 
     /**
@@ -269,14 +289,11 @@
      * @param row the row to read from, row - getStartPosition() being the actual row in the window
      * @param col the column to read from
      * @return {@code true} if given field is a long
+     * @deprecated use {@link #getType(int, int)} instead
      */
+    @Deprecated
     public boolean isLong(int row, int col) {
-        acquireReference();
-        try {
-            return isInteger_native(row - mStartPos, col);
-        } finally {
-            releaseReference();
-        }
+        return getType(row, col) == Cursor.FIELD_TYPE_INTEGER;
     }
 
     /**
@@ -285,14 +302,11 @@
      * @param row the row to read from, row - getStartPosition() being the actual row in the window
      * @param col the column to read from
      * @return {@code true} if given field is a float
+     * @deprecated use {@link #getType(int, int)} instead
      */
+    @Deprecated
     public boolean isFloat(int row, int col) {
-        acquireReference();
-        try {
-            return isFloat_native(row - mStartPos, col);
-        } finally {
-            releaseReference();
-        }
+        return getType(row, col) == Cursor.FIELD_TYPE_FLOAT;
     }
 
     /**
@@ -301,20 +315,18 @@
      * @param row the row to read from, row - getStartPosition() being the actual row in the window
      * @param col the column to read from
      * @return {@code true} if given field is {@code NULL} or a String
+     * @deprecated use {@link #getType(int, int)} instead
      */
+    @Deprecated
     public boolean isString(int row, int col) {
-        acquireReference();
-        try {
-            return isString_native(row - mStartPos, col);
-        } finally {
-            releaseReference();
-        }
+        return getType(row, col) == Cursor.FIELD_TYPE_STRING;
     }
 
     private native boolean isBlob_native(int row, int col);
     private native boolean isString_native(int row, int col);
     private native boolean isInteger_native(int row, int col);
     private native boolean isFloat_native(int row, int col);
+    private native int getType_native(int row, int col);
 
     /**
      * Returns a String for the given field.
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 633b2b3..2ac9470 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -130,6 +130,10 @@
         return mCursor.isLast();
     }
 
+    public int getType(int columnIndex) {
+        return mCursor.getType(columnIndex);
+    }
+
     public boolean isNull(int columnIndex) {
         return mCursor.isNull(columnIndex);
     }
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 9bfbb74..af93eee 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -193,6 +193,37 @@
     }
 
     /**
+     * Returns data type of the given object's value.
+     *<p>
+     * Returned values are
+     * <ul>
+     *   <li>{@link Cursor#FIELD_TYPE_NULL}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_STRING}</li>
+     *   <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
+     *</ul>
+     *</p>
+     *
+     * @param obj the object whose value type is to be returned
+     * @return object value type
+     * @hide
+     */
+    public static int getTypeOfObject(Object obj) {
+        if (obj == null) {
+            return Cursor.FIELD_TYPE_NULL;
+        } else if (obj instanceof byte[]) {
+            return Cursor.FIELD_TYPE_BLOB;
+        } else if (obj instanceof Float || obj instanceof Double) {
+            return Cursor.FIELD_TYPE_FLOAT;
+        } else if (obj instanceof Long || obj instanceof Integer) {
+            return Cursor.FIELD_TYPE_INTEGER;
+        } else {
+            return Cursor.FIELD_TYPE_STRING;
+        }
+    }
+
+    /**
      * Appends an SQL string to the given StringBuilder, including the opening
      * and closing single quotes. Any single quotes internal to sqlString will
      * be escaped.
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index d5c3a32..5c1b968 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -272,6 +272,11 @@
     }
 
     @Override
+    public int getType(int column) {
+        return DatabaseUtils.getTypeOfObject(get(column));
+    }
+
+    @Override
     public boolean isNull(int column) {
         return get(column) == null;
     }
diff --git a/core/java/android/database/MergeCursor.java b/core/java/android/database/MergeCursor.java
index cb6d7ac..2c25db7 100644
--- a/core/java/android/database/MergeCursor.java
+++ b/core/java/android/database/MergeCursor.java
@@ -129,6 +129,11 @@
     }
 
     @Override
+    public int getType(int column) {
+        return mCursor.getType(column);
+    }
+
+    @Override
     public boolean isNull(int column)
     {
         return mCursor.isNull(column);
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 886951b..f7f8004 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -34,6 +34,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import dalvik.system.BlockGuard;
+
 import java.io.File;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -244,26 +246,26 @@
     private static int sBlockSize = 0;
 
     /** The path for the database file */
-    private String mPath;
+    private final String mPath;
 
     /** The anonymized path for the database file for logging purposes */
     private String mPathForLogs = null;  // lazily populated
 
     /** The flags passed to open/create */
-    private int mFlags;
+    private final int mFlags;
 
     /** The optional factory to use when creating new Cursors */
-    private CursorFactory mFactory;
+    private final CursorFactory mFactory;
 
-    private WeakHashMap<SQLiteClosable, Object> mPrograms;
+    private final WeakHashMap<SQLiteClosable, Object> mPrograms;
 
     /**
      * for each instance of this class, a LRU cache is maintained to store
      * the compiled query statement ids returned by sqlite database.
-     *     key = sql statement with "?" for bind args
+     *     key = SQL statement with "?" for bind args
      *     value = {@link SQLiteCompiledSql}
      * If an application opens the database and keeps it open during its entire life, then
-     * there will not be an overhead of compilation of sql statements by sqlite.
+     * there will not be an overhead of compilation of SQL statements by sqlite.
      *
      * why is this cache NOT static? because sqlite attaches compiledsql statements to the
      * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
@@ -274,7 +276,7 @@
      */
     // default statement-cache size per database connection ( = instance of this class)
     private int mMaxSqlCacheSize = 25;
-    /* package */ Map<String, SQLiteCompiledSql> mCompiledQueries =
+    /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries =
         new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) {
             @Override
             public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) {
@@ -303,7 +305,7 @@
     /**
      * absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}
      * size of each prepared-statement is between 1K - 6K, depending on the complexity of the
-     * sql statement & schema.
+     * SQL statement & schema.
      */
     public static final int MAX_SQL_CACHE_SIZE = 100;
     private int mCacheFullWarnings;
@@ -314,19 +316,19 @@
     private int mNumCacheMisses;
 
     /** Used to find out where this object was created in case it never got closed. */
-    private Throwable mStackTrace = null;
+    private final Throwable mStackTrace;
 
     // System property that enables logging of slow queries. Specify the threshold in ms.
     private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
     private final int mSlowQueryThreshold;
 
     /** stores the list of statement ids that need to be finalized by sqlite */
-    private ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>();
+    private final ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>();
 
     /** {@link DatabaseErrorHandler} to be used when SQLite returns any of the following errors
      *    Corruption
      * */
-    private DatabaseErrorHandler errorHandler;
+    private final DatabaseErrorHandler mErrorHandler;
 
     /**
      * @param closable
@@ -383,7 +385,7 @@
 
     /* package */ void onCorruption() {
         EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
-        errorHandler.onCorruption(this);
+        mErrorHandler.onCorruption(this);
     }
 
     /**
@@ -481,11 +483,14 @@
     }
 
     /**
-     * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
+     * Begins a transaction in EXCLUSIVE mode.
+     * <p>
+     * Transactions can be nested.
+     * When the outer transaction is ended all of
      * the work done in that transaction and all of the nested transactions will be committed or
      * rolled back. The changes will be rolled back if any transaction is ended without being
      * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
-     *
+     * </p>
      * <p>Here is the standard idiom for transactions:
      *
      * <pre>
@@ -503,11 +508,14 @@
     }
 
     /**
-     * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
+     * Begins a transaction in EXCLUSIVE mode.
+     * <p>
+     * Transactions can be nested.
+     * When the outer transaction is ended all of
      * the work done in that transaction and all of the nested transactions will be committed or
      * rolled back. The changes will be rolled back if any transaction is ended without being
      * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
-     *
+     * </p>
      * <p>Here is the standard idiom for transactions:
      *
      * <pre>
@@ -519,15 +527,14 @@
      *     db.endTransaction();
      *   }
      * </pre>
+     *
      * @param transactionListener listener that should be notified when the transaction begins,
      * commits, or is rolled back, either explicitly or by a call to
      * {@link #yieldIfContendedSafely}.
      */
     public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
+        verifyDbIsOpen();
         lockForced();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
         boolean ok = false;
         try {
             // If this thread already had the lock then get out
@@ -572,12 +579,7 @@
      * are committed and rolled back.
      */
     public void endTransaction() {
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
-        if (!mLock.isHeldByCurrentThread()) {
-            throw new IllegalStateException("no transaction pending");
-        }
+        verifyLockOwner();
         try {
             if (mInnerTransactionIsSuccessful) {
                 mInnerTransactionIsSuccessful = false;
@@ -635,9 +637,7 @@
      * transaction is already marked as successful.
      */
     public void setTransactionSuccessful() {
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
+        verifyDbIsOpen();
         if (!mLock.isHeldByCurrentThread()) {
             throw new IllegalStateException("no transaction pending");
         }
@@ -839,17 +839,27 @@
     }
 
     /**
-     * same as {@link #openDatabase(String, CursorFactory, int)} except for an additional param
-     * errorHandler.
-     * @param errorHandler the {@link DatabaseErrorHandler} obj to be used when database
-     * corruption is detected on the database.
+     * Open the database according to the flags {@link #OPEN_READWRITE}
+     * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
+     *
+     * <p>Sets the locale of the database to the  the system's current locale.
+     * Call {@link #setLocale} if you would like something else.</p>
+     *
+     * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
+     * used to handle corruption when sqlite reports database corruption.</p>
+     *
+     * @param path to database file to open and/or create
+     * @param factory an optional factory class that is called to instantiate a
+     *            cursor when query is called, or null for default
+     * @param flags to control database access mode
+     * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
+     * when sqlite reports database corruption
+     * @return the newly opened database
+     * @throws SQLiteException if the database cannot be opened
      */
     public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
             DatabaseErrorHandler errorHandler) {
-        SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags);
-
-        // set the ErrorHandler to be used when SQLite reports exceptions
-        sqliteDatabase.errorHandler = errorHandler;
+        SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags, errorHandler);
 
         try {
             // Open the database.
@@ -863,7 +873,7 @@
         } catch (SQLiteDatabaseCorruptException e) {
             // Database is not even openable.
             errorHandler.onCorruption(sqliteDatabase);
-            sqliteDatabase = new SQLiteDatabase(path, factory, flags);
+            sqliteDatabase = new SQLiteDatabase(path, factory, flags, errorHandler);
         }
 
         // set sqlite pagesize to mBlockSize
@@ -874,8 +884,8 @@
         }
         sqliteDatabase.setPageSize(sBlockSize);
 
-        ActiveDatabases.getInstance().mActiveDatabases.add(
-                new WeakReference<SQLiteDatabase>(sqliteDatabase));
+        // add this database to the list of databases opened in this process
+        ActiveDatabases.addActiveDatabase(sqliteDatabase);
         return sqliteDatabase;
     }
 
@@ -952,7 +962,7 @@
     }
 
     private void closeClosable() {
-        /* deallocate all compiled sql statement objects from mCompiledQueries cache.
+        /* deallocate all compiled SQL statement objects from mCompiledQueries cache.
          * this should be done before de-referencing all {@link SQLiteClosable} objects
          * from this database object because calling
          * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database
@@ -982,19 +992,7 @@
      * @return the database version
      */
     public int getVersion() {
-        SQLiteStatement prog = null;
-        lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
-        try {
-            prog = new SQLiteStatement(this, "PRAGMA user_version;");
-            long version = prog.simpleQueryForLong();
-            return (int) version;
-        } finally {
-            if (prog != null) prog.close();
-            unlock();
-        }
+        return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
     }
 
     /**
@@ -1012,20 +1010,8 @@
      * @return the new maximum database size
      */
     public long getMaximumSize() {
-        SQLiteStatement prog = null;
-        lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
-        try {
-            prog = new SQLiteStatement(this,
-                    "PRAGMA max_page_count;");
-            long pageCount = prog.simpleQueryForLong();
-            return pageCount * getPageSize();
-        } finally {
-            if (prog != null) prog.close();
-            unlock();
-        }
+        long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null);
+        return pageCount * getPageSize();
     }
 
     /**
@@ -1036,26 +1022,15 @@
      * @return the new maximum database size
      */
     public long setMaximumSize(long numBytes) {
-        SQLiteStatement prog = null;
-        lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
+        long pageSize = getPageSize();
+        long numPages = numBytes / pageSize;
+        // If numBytes isn't a multiple of pageSize, bump up a page
+        if ((numBytes % pageSize) != 0) {
+            numPages++;
         }
-        try {
-            long pageSize = getPageSize();
-            long numPages = numBytes / pageSize;
-            // If numBytes isn't a multiple of pageSize, bump up a page
-            if ((numBytes % pageSize) != 0) {
-                numPages++;
-            }
-            prog = new SQLiteStatement(this,
-                    "PRAGMA max_page_count = " + numPages);
-            long newPageCount = prog.simpleQueryForLong();
-            return newPageCount * pageSize;
-        } finally {
-            if (prog != null) prog.close();
-            unlock();
-        }
+        long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages,
+                null);
+        return newPageCount * pageSize;
     }
 
     /**
@@ -1064,20 +1039,7 @@
      * @return the database page size, in bytes
      */
     public long getPageSize() {
-        SQLiteStatement prog = null;
-        lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
-        try {
-            prog = new SQLiteStatement(this,
-                    "PRAGMA page_size;");
-            long size = prog.simpleQueryForLong();
-            return size;
-        } finally {
-            if (prog != null) prog.close();
-            unlock();
-        }
+        return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null);
     }
 
     /**
@@ -1165,7 +1127,7 @@
         if (info != null) {
             execSQL("UPDATE " + info.masterTable
                     + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
-                    + " FROM " + table + " WHERE _id=" + rowId + ")");
+                    + " FROM " + table + " WHERE _id=?)", new String[] {String.valueOf(rowId)});
         }
     }
 
@@ -1205,10 +1167,8 @@
      * {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
      */
     public SQLiteStatement compileStatement(String sql) throws SQLException {
+        verifyDbIsOpen();
         lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
         try {
             return new SQLiteStatement(this, sql);
         } finally {
@@ -1290,9 +1250,7 @@
             boolean distinct, String table, String[] columns,
             String selection, String[] selectionArgs, String groupBy,
             String having, String orderBy, String limit) {
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
+        verifyDbIsOpen();
         String sql = SQLiteQueryBuilder.buildQueryString(
                 distinct, table, columns, selection, groupBy, having, orderBy, limit);
 
@@ -1403,9 +1361,8 @@
     public Cursor rawQueryWithFactory(
             CursorFactory cursorFactory, String sql, String[] selectionArgs,
             String editTable) {
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
+        verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onReadFromDisk();
         long timeStart = 0;
 
         if (Config.LOGV || mSlowQueryThreshold != -1) {
@@ -1564,9 +1521,8 @@
      */
     public long insertWithOnConflict(String table, String nullColumnHack,
             ContentValues initialValues, int conflictAlgorithm) {
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
+        verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onWriteToDisk();
 
         // Measurements show most sql lengths <= 152
         StringBuilder sql = new StringBuilder(152);
@@ -1655,10 +1611,9 @@
      *         whereClause.
      */
     public int delete(String table, String whereClause, String[] whereArgs) {
+        verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
         SQLiteStatement statement = null;
         try {
             statement = compileStatement("DELETE FROM " + table
@@ -1710,6 +1665,7 @@
      */
     public int updateWithOnConflict(String table, ContentValues values,
             String whereClause, String[] whereArgs, int conflictAlgorithm) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (values == null || values.size() == 0) {
             throw new IllegalArgumentException("Empty values");
         }
@@ -1737,10 +1693,8 @@
             sql.append(whereClause);
         }
 
+        verifyDbIsOpen();
         lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
         SQLiteStatement statement = null;
         try {
             statement = compileStatement(sql.toString());
@@ -1785,18 +1739,25 @@
     }
 
     /**
-     * Execute a single SQL statement that is not a query. For example, CREATE
-     * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
-     * supported. it takes a write lock
+     * Execute a single SQL statement that is NOT a SELECT
+     * or any other SQL statement that returns data.
+     * <p>
+     * Use of this method is discouraged as it doesn't perform well when issuing the same SQL
+     * statement repeatedly (see {@link #compileStatement(String)} to prepare statements for
+     * repeated use), and it has no means to return any data (such as the number of affected rows).
+     * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)},
+     * {@link #update(String, ContentValues, String, String[])}, et al, when possible.
+     * </p>
      *
+     * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
+     * not supported.
      * @throws SQLException If the SQL string is invalid for some reason
      */
     public void execSQL(String sql) throws SQLException {
+        verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         long timeStart = SystemClock.uptimeMillis();
         lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
         logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX);
         try {
             closePendingStatements();
@@ -1819,23 +1780,50 @@
     }
 
     /**
-     * Execute a single SQL statement that is not a query. For example, CREATE
-     * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
-     * supported. it takes a write lock,
+     * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
+     * <p>
+     * For INSERT statements, use any of the following instead.
+     * <ul>
+     *   <li>{@link #insert(String, String, ContentValues)}</li>
+     *   <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
+     *   <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
+     * </ul>
+     * <p>
+     * For UPDATE statements, use any of the following instead.
+     * <ul>
+     *   <li>{@link #update(String, ContentValues, String, String[])}</li>
+     *   <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
+     * </ul>
+     * <p>
+     * For DELETE statements, use any of the following instead.
+     * <ul>
+     *   <li>{@link #delete(String, String, String[])}</li>
+     * </ul>
+     * <p>
+     * For example, the following are good candidates for using this method:
+     * <ul>
+     *   <li>ALTER TABLE</li>
+     *   <li>CREATE or DROP table / trigger / view / index / virtual table</li>
+     *   <li>REINDEX</li>
+     *   <li>RELEASE</li>
+     *   <li>SAVEPOINT</li>
+     *   <li>PRAGMA that returns no data</li>
+     * </ul>
+     * </p>
      *
-     * @param sql
+     * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
+     * not supported.
      * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
      * @throws SQLException If the SQL string is invalid for some reason
      */
     public void execSQL(String sql, Object[] bindArgs) throws SQLException {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (bindArgs == null) {
             throw new IllegalArgumentException("Empty bindArgs");
         }
+        verifyDbIsOpen();
         long timeStart = SystemClock.uptimeMillis();
         lock();
-        if (!isOpen()) {
-            throw new IllegalStateException("database not open");
-        }
         SQLiteStatement statement = null;
         try {
             statement = compileStatement(sql);
@@ -1869,14 +1857,17 @@
     }
 
     /**
-     * Private constructor. See {@link #create} and {@link #openDatabase}.
+     * Private constructor.
      *
      * @param path The full path to the database
      * @param factory The factory to use when creating cursors, may be NULL.
      * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}.  If the database file already
      *              exists, mFlags will be updated appropriately.
+     * @param errorHandler The {@link DatabaseErrorHandler} to be used when sqlite reports database
+     * corruption. may be NULL.
      */
-    private SQLiteDatabase(String path, CursorFactory factory, int flags) {
+    private SQLiteDatabase(String path, CursorFactory factory, int flags,
+            DatabaseErrorHandler errorHandler) {
         if (path == null) {
             throw new IllegalArgumentException("path should not be null");
         }
@@ -1886,6 +1877,9 @@
         mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
         mFactory = factory;
         mPrograms = new WeakHashMap<SQLiteClosable,Object>();
+        // Set the DatabaseErrorHandler to be used when SQLite reports corruption.
+        // If the caller sets errorHandler = null, then use default errorhandler.
+        mErrorHandler = (errorHandler == null) ? new DefaultDatabaseErrorHandler() : errorHandler;
     }
 
     /**
@@ -2011,11 +2005,15 @@
         }
     }
 
-    /* package */ void verifyLockOwner() {
+    /* package */ void verifyDbIsOpen() {
         if (!isOpen()) {
             throw new IllegalStateException("database " + getPath() + " already closed");
         }
-        if (!isDbLockedByCurrentThread() && mLockingEnabled) {
+    }
+
+    /* package */ void verifyLockOwner() {
+        verifyDbIsOpen();
+        if (mLockingEnabled && !isDbLockedByCurrentThread()) {
             throw new IllegalStateException("Don't have database lock!");
         }
     }
@@ -2027,10 +2025,10 @@
      * ============================================================================
      */
     /**
-     * adds the given sql and its compiled-statement-id-returned-by-sqlite to the
+     * Adds the given SQL and its compiled-statement-id-returned-by-sqlite to the
      * cache of compiledQueries attached to 'this'.
-     *
-     * if there is already a {@link SQLiteCompiledSql} in compiledQueries for the given sql,
+     * <p>
+     * If there is already a {@link SQLiteCompiledSql} in compiledQueries for the given SQL,
      * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current
      * mapping is NOT replaced with the new mapping).
      */
@@ -2076,8 +2074,8 @@
     }
 
     /**
-     * from the compiledQueries cache, returns the compiled-statement-id for the given sql.
-     * returns null, if not found in the cache.
+     * From the compiledQueries cache, returns the compiled-statement-id for the given SQL.
+     * Returns null, if not found in the cache.
      */
     /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
         SQLiteCompiledSql compiledStatement = null;
@@ -2101,14 +2099,15 @@
     }
 
     /**
-     * set the max size of the prepared-statement cache for this database.
+     * Sets the maximum size of the prepared-statement cache for this database.
      * (size of the cache = number of compiled-sql-statements stored in the cache).
+     *<p>
+     * Maximum cache size can ONLY be increased from its current size (default = 10).
+     * If this method is called with smaller size than the current maximum value,
+     * then IllegalStateException is thrown.
+     *<p>
+     * This method is thread-safe.
      *
-     * max cache size can ONLY be increased from its current size (default = 10).
-     * if this method is called with smaller size than the current value of mMaxSqlCacheSize,
-     * then IllegalStateException is thrown
-     *
-     * synchronized because we don't want t threads to change cache size at the same time.
      * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE})
      * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE} or
      * > the value set with previous setMaxSqlCacheSize() call.
@@ -2172,9 +2171,14 @@
     static class ActiveDatabases {
         private static final ActiveDatabases activeDatabases = new ActiveDatabases();
         private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases =
-            new HashSet<WeakReference<SQLiteDatabase>>();
+                new HashSet<WeakReference<SQLiteDatabase>>();
         private ActiveDatabases() {} // disable instantiation of this class
-        static ActiveDatabases getInstance() {return activeDatabases;}
+        static ActiveDatabases getInstance() {
+            return activeDatabases;
+        }
+        private static void addActiveDatabase(SQLiteDatabase sqliteDatabase) {
+            activeDatabases.mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase));
+        }
     }
 
     /**
@@ -2188,70 +2192,59 @@
             if (db == null || !db.isOpen()) {
                 continue;
             }
-            // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
-            int lookasideUsed = db.native_getDbLookaside();
 
-            // get the lastnode of the dbname
-            String path = db.getPath();
-            int indx = path.lastIndexOf("/");
-            String lastnode = path.substring((indx != -1) ? ++indx : 0);
+            try {
+                // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
+                int lookasideUsed = db.native_getDbLookaside();
 
-            // get list of attached dbs and for each db, get its size and pagesize
-            ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs();
-            if (attachedDbs == null) {
-                continue;
-            }
-            for (int i = 0; i < attachedDbs.size(); i++) {
-                Pair<String, String> p = attachedDbs.get(i);
-                long pageCount = getPragmaVal(db, p.first + ".page_count;");
+                // get the lastnode of the dbname
+                String path = db.getPath();
+                int indx = path.lastIndexOf("/");
+                String lastnode = path.substring((indx != -1) ? ++indx : 0);
 
-                // first entry in the attached db list is always the main database
-                // don't worry about prefixing the dbname with "main"
-                String dbName;
-                if (i == 0) {
-                    dbName = lastnode;
-                } else {
-                    // lookaside is only relevant for the main db
-                    lookasideUsed = 0;
-                    dbName = "  (attached) " + p.first;
-                    // if the attached db has a path, attach the lastnode from the path to above
-                    if (p.second.trim().length() > 0) {
-                        int idx = p.second.lastIndexOf("/");
-                        dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
+                // get list of attached dbs and for each db, get its size and pagesize
+                ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs();
+                if (attachedDbs == null) {
+                    continue;
+                }
+                for (int i = 0; i < attachedDbs.size(); i++) {
+                    Pair<String, String> p = attachedDbs.get(i);
+                    long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first
+                            + ".page_count;", null);
+
+                    // first entry in the attached db list is always the main database
+                    // don't worry about prefixing the dbname with "main"
+                    String dbName;
+                    if (i == 0) {
+                        dbName = lastnode;
+                    } else {
+                        // lookaside is only relevant for the main db
+                        lookasideUsed = 0;
+                        dbName = "  (attached) " + p.first;
+                        // if the attached db has a path, attach the lastnode from the path to above
+                        if (p.second.trim().length() > 0) {
+                            int idx = p.second.lastIndexOf("/");
+                            dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
+                        }
+                    }
+                    if (pageCount > 0) {
+                        dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
+                                lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses,
+                                db.mCompiledQueries.size()));
                     }
                 }
-                if (pageCount > 0) {
-                    dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
-                            lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses,
-                            db.mCompiledQueries.size()));
-                }
+            } catch (SQLiteException e) {
+                // ignore. we don't care about exceptions when we are taking adb
+                // bugreport!
             }
         }
         return dbStatsList;
     }
 
     /**
-     * get the specified pragma value from sqlite for the specified database.
-     * only handles pragma's that return int/long.
-     * NO JAVA locks are held in this method.
-     * TODO: use this to do all pragma's in this class
-     */
-    private static long getPragmaVal(SQLiteDatabase db, String pragma) {
-        if (!db.isOpen()) {
-            return 0;
-        }
-        SQLiteStatement prog = null;
-        try {
-            prog = new SQLiteStatement(db, "PRAGMA " + pragma);
-            long val = prog.simpleQueryForLong();
-            return val;
-        } finally {
-            if (prog != null) prog.close();
-        }
-    }
-
-    /**
-     * returns list of full pathnames of all attached databases including the main database
+     * Returns list of full pathnames of all attached databases including the main database
+     * by executing 'pragma database_list' on the database.
+     *
      * @return ArrayList of pairs of (database name, database file path) or null if the database
      * is not open.
      */
@@ -2280,20 +2273,20 @@
     }
 
     /**
-     * run pragma integrity_check on the given database (and all the attached databases)
-     * and return true if the given database (and all its attached databases) pass integrity_check,
+     * Runs 'pragma integrity_check' on the given database (and all the attached databases)
+     * and returns true if the given database (and all its attached databases) pass integrity_check,
      * false otherwise.
-     *
-     * if the result is false, then this method logs the errors reported by the integrity_check
+     *<p>
+     * If the result is false, then this method logs the errors reported by the integrity_check
      * command execution.
+     *<p>
+     * Note that 'pragma integrity_check' on a database can take a long time.
      *
      * @return true if the given database (and all its attached databases) pass integrity_check,
-     * false otherwise
+     * false otherwise.
      */
     public boolean isDatabaseIntegrityOk() {
-        if (!isOpen()) {
-            throw new IllegalStateException("database: " + getPath() + " is NOT open");
-        }
+        verifyDbIsOpen();
         ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs();
         if (attachedDbs == null) {
             throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " +
@@ -2326,16 +2319,16 @@
     private native void dbopen(String path, int flags);
 
     /**
-     * Native call to setup tracing of all sql statements
+     * Native call to setup tracing of all SQL statements
      *
      * @param path the full path to the database
      */
     private native void enableSqlTracing(String path);
 
     /**
-     * Native call to setup profiling of all sql statements.
+     * Native call to setup profiling of all SQL statements.
      * currently, sqlite's profiling = printing of execution-time
-     * (wall-clock time) of each of the sql statements, as they
+     * (wall-clock time) of each of the SQL statements, as they
      * are executed.
      *
      * @param path the full path to the database
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index d4907d9..851f5ea 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -17,6 +17,8 @@
 package android.database.sqlite;
 
 import android.content.Context;
+import android.database.DatabaseErrorHandler;
+import android.database.DefaultDatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.util.Log;
 
@@ -39,6 +41,7 @@
 
     private SQLiteDatabase mDatabase = null;
     private boolean mIsInitializing = false;
+    private final DatabaseErrorHandler mErrorHandler;
 
     /**
      * Create a helper object to create, open, and/or manage a database.
@@ -52,12 +55,37 @@
      *     {@link #onUpgrade} will be used to upgrade the database
      */
     public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
+        this(context, name, factory, version, new DefaultDatabaseErrorHandler());
+    }
+
+    /**
+     * Create a helper object to create, open, and/or manage a database.
+     * The database is not actually created or opened until one of
+     * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
+     *
+     * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
+     * used to handle corruption when sqlite reports database corruption.</p>
+     *
+     * @param context to use to open or create the database
+     * @param name of the database file, or null for an in-memory database
+     * @param factory to use for creating cursor objects, or null for the default
+     * @param version number of the database (starting at 1); if the database is older,
+     *     {@link #onUpgrade} will be used to upgrade the database
+     * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
+     * corruption.
+     */
+    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
+            DatabaseErrorHandler errorHandler) {
         if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
+        if (errorHandler == null) {
+            throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
+        }
 
         mContext = context;
         mName = name;
         mFactory = factory;
         mNewVersion = version;
+        mErrorHandler = errorHandler;
     }
 
     /**
@@ -95,7 +123,7 @@
             if (mName == null) {
                 db = SQLiteDatabase.create(null);
             } else {
-                db = mContext.openOrCreateDatabase(mName, 0, mFactory);
+                db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
             }
 
             int version = db.getVersion();
@@ -169,7 +197,8 @@
         try {
             mIsInitializing = true;
             String path = mContext.getDatabasePath(mName).getPath();
-            db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);
+            db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY,
+                    mErrorHandler);
             if (db.getVersion() != mNewVersion) {
                 throw new SQLiteException("Can't upgrade read-only database from version " +
                         db.getVersion() + " to " + mNewVersion + ": " + path);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index dc1a0ee..a3513e6 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -20,7 +20,7 @@
 
 /**
  * A base class for compiled SQLite programs.
- *
+ *<p>
  * SQLiteProgram is not internally synchronized so code using a SQLiteProgram from multiple
  * threads should perform its own synchronization when using the SQLiteProgram.
  */
@@ -176,9 +176,7 @@
      * @param index The 1-based index to the parameter to bind null to
      */
     public void bindNull(int index) {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
         acquireReference();
         try {
             native_bind_null(index);
@@ -195,9 +193,7 @@
      * @param value The value to bind
      */
     public void bindLong(int index, long value) {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
         acquireReference();
         try {
             native_bind_long(index, value);
@@ -214,9 +210,7 @@
      * @param value The value to bind
      */
     public void bindDouble(int index, double value) {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
         acquireReference();
         try {
             native_bind_double(index, value);
@@ -236,9 +230,7 @@
         if (value == null) {
             throw new IllegalArgumentException("the bind value at index " + index + " is null");
         }
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
         acquireReference();
         try {
             native_bind_string(index, value);
@@ -258,9 +250,7 @@
         if (value == null) {
             throw new IllegalArgumentException("the bind value at index " + index + " is null");
         }
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
         acquireReference();
         try {
             native_bind_blob(index, value);
@@ -273,9 +263,7 @@
      * Clears all existing bindings. Unset bindings are treated as NULL.
      */
     public void clearBindings() {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
         acquireReference();
         try {
             native_clear_bindings();
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index ba0e63b..e1ad306c 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -18,12 +18,14 @@
 
 import android.os.SystemClock;
 
+import dalvik.system.BlockGuard;
+
 /**
  * A pre-compiled statement against a {@link SQLiteDatabase} that can be reused.
  * The statement cannot return multiple rows, but 1x1 result sets are allowed.
  * Don't use SQLiteStatement constructor directly, please use
  * {@link SQLiteDatabase#compileStatement(String)}
- *
+ *<p>
  * SQLiteStatement is not internally synchronized so code using a SQLiteStatement from multiple
  * threads should perform its own synchronization when using the SQLiteStatement.
  */
@@ -47,9 +49,8 @@
      *         some reason
      */
     public void execute() {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         long timeStart = SystemClock.uptimeMillis();
         mDatabase.lock();
 
@@ -74,9 +75,8 @@
      *         some reason
      */
     public long executeInsert() {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         long timeStart = SystemClock.uptimeMillis();
         mDatabase.lock();
 
@@ -101,9 +101,8 @@
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
     public long simpleQueryForLong() {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onReadFromDisk();
         long timeStart = SystemClock.uptimeMillis();
         mDatabase.lock();
 
@@ -128,9 +127,8 @@
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
     public String simpleQueryForString() {
-        if (!mDatabase.isOpen()) {
-            throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
-        }
+        mDatabase.verifyDbIsOpen();
+        BlockGuard.getThreadPolicy().onReadFromDisk();
         long timeStart = SystemClock.uptimeMillis();
         mDatabase.lock();
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 46e1f89..025db4a 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -763,6 +763,7 @@
         private static final String KEY_ZOOM_SUPPORTED = "zoom-supported";
         private static final String KEY_SMOOTH_ZOOM_SUPPORTED = "smooth-zoom-supported";
         private static final String KEY_FOCUS_DISTANCES = "focus-distances";
+        private static final String KEY_METERING_MODE = "metering-mode";
 
         // Parameter key suffix for supported values.
         private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -825,21 +826,81 @@
          */
         public static final String FLASH_MODE_TORCH = "torch";
 
-        // Values for scene mode settings.
+        /**
+         * Scene mode is off.
+         */
         public static final String SCENE_MODE_AUTO = "auto";
+
+        /**
+         * Take photos of fast moving objects. Same as {@link
+         * #SCENE_MODE_SPORTS}.
+         */
         public static final String SCENE_MODE_ACTION = "action";
+
+        /**
+         * Take people pictures.
+         */
         public static final String SCENE_MODE_PORTRAIT = "portrait";
+
+        /**
+         * Take pictures on distant objects.
+         */
         public static final String SCENE_MODE_LANDSCAPE = "landscape";
+
+        /**
+         * Take photos at night.
+         */
         public static final String SCENE_MODE_NIGHT = "night";
+
+        /**
+         * Take people pictures at night.
+         */
         public static final String SCENE_MODE_NIGHT_PORTRAIT = "night-portrait";
+
+        /**
+         * Take photos in a theater. Flash light is off.
+         */
         public static final String SCENE_MODE_THEATRE = "theatre";
+
+        /**
+         * Take pictures on the beach.
+         */
         public static final String SCENE_MODE_BEACH = "beach";
+
+        /**
+         * Take pictures on the snow.
+         */
         public static final String SCENE_MODE_SNOW = "snow";
+
+        /**
+         * Take sunset photos.
+         */
         public static final String SCENE_MODE_SUNSET = "sunset";
+
+        /**
+         * Avoid blurry pictures (for example, due to hand shake).
+         */
         public static final String SCENE_MODE_STEADYPHOTO = "steadyphoto";
+
+        /**
+         * For shooting firework displays.
+         */
         public static final String SCENE_MODE_FIREWORKS = "fireworks";
+
+        /**
+         * Take photos of fast moving objects. Same as {@link
+         * #SCENE_MODE_ACTION}.
+         */
         public static final String SCENE_MODE_SPORTS = "sports";
+
+        /**
+         * Take indoor low-light shot.
+         */
         public static final String SCENE_MODE_PARTY = "party";
+
+        /**
+         * Capture the naturally warm color of scenes lit by candles.
+         */
         public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
 
         /**
@@ -905,6 +966,26 @@
          */
         public static final String FOCUS_MODE_CONTINUOUS = "continuous";
 
+        /**
+         * The camera determines the exposure by giving more weight to the
+         * central part of the scene.
+         * @hide
+         */
+        public static final String METERING_MODE_CENTER_WEIGHTED = "center-weighted";
+
+        /**
+         * The camera determines the exposure by averaging the entire scene,
+         * giving no weighting to any particular area.
+         * @hide
+         */
+        public static final String METERING_MODE_FRAME_AVERAGE = "frame-average";
+
+        /**
+         * The camera determines the exposure by a very small area of the scene,
+         * typically the center.
+         * @hide
+         */
+        public static final String METERING_MODE_SPOT = "spot";
 
         // Formats for setPreviewFormat and setPictureFormat.
         private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
@@ -1870,6 +1951,45 @@
             output[2] = distances.get(2);
         }
 
+        /**
+         * Gets the supported metering modes.
+         *
+         * @return a list of supported metering modes. null if metering mode
+         *         setting is not supported.
+         * @see #getMeteringMode()
+         * @hide
+         */
+        public List<String> getSupportedMeteringModes() {
+            String str = get(KEY_METERING_MODE + SUPPORTED_VALUES_SUFFIX);
+            return split(str);
+        }
+
+        /**
+         * Gets the current metering mode, which affects how camera determines
+         * exposure.
+         *
+         * @return current metering mode. If the camera does not support
+         *         metering setting, this should return null.
+         * @see #METERING_MODE_CENTER_WEIGHTED
+         * @see #METERING_MODE_FRAME_AVERAGE
+         * @see #METERING_MODE_SPOT
+         * @hide
+         */
+        public String getMeteringMode() {
+            return get(KEY_METERING_MODE);
+        }
+
+        /**
+         * Sets the metering mode.
+         *
+         * @param value metering mode.
+         * @see #getMeteringMode()
+         * @hide
+         */
+        public void setMeteringMode(String value) {
+            set(KEY_METERING_MODE, value);
+        }
+
         // Splits a comma delimited string to an ArrayList of String.
         // Return null if the passing string is null or the size is 0.
         private ArrayList<String> split(String str) {
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index e74697a..823134b 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -401,6 +401,9 @@
      * publish updates on the UI thread while the background computation is
      * still running. Each call to this method will trigger the execution of
      * {@link #onProgressUpdate} on the UI thread.
+     * 
+     * {@link #onProgressUpdate} will note be called if the task has been
+     * canceled.
      *
      * @param values The progress values to update the UI with.
      *
@@ -408,8 +411,10 @@
      * @see #doInBackground
      */
     protected final void publishProgress(Progress... values) {
-        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
-                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+        if (!isCancelled()) {
+            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+        }
     }
 
     private void finish(Result result) {
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 7e99f38..667ce68 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -24,33 +24,52 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 
+/**
+ * Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
+ * to fire an event after files are accessed or changed by by any process on
+ * the device (including this one).  FileObserver is an abstract class;
+ * subclasses must implement the event handler {@link #onEvent(int, String)}.
+ *
+ * <p>Each FileObserver instance monitors a single file or directory.
+ * If a directory is monitored, events will be triggered for all files and
+ * subdirectories (recursively) inside the monitored directory.</p>
+ *
+ * <p>An event mask is used to specify which changes or actions to report.
+ * Event type constants are used to describe the possible changes in the
+ * event mask as well as what actually happened in event callbacks.</p>
+ *
+ * <p class="caution"><b>Warning</b>: If a FileObserver is garbage collected, it
+ * will stop sending events.  To ensure you keep receiving events, you must
+ * keep a reference to the FileObserver instance from some other live object.</p>
+ */
 public abstract class FileObserver {
-    /** File was accessed */
+    /** Event type: Data was read from a file */
     public static final int ACCESS = 0x00000001;
-    /** File was modified */
+    /** Event type: Data was written to a file */
     public static final int MODIFY = 0x00000002;
-    /** Metadata changed */
+    /** Event type: Metadata (permissions, owner, timestamp) was changed explicitly */
     public static final int ATTRIB = 0x00000004;
-    /** Writable file was closed */
+    /** Event type: Someone had a file or directory open for writing, and closed it */
     public static final int CLOSE_WRITE = 0x00000008;
-    /** Unwrittable file closed */
+    /** Event type: Someone had a file or directory open read-only, and closed it */
     public static final int CLOSE_NOWRITE = 0x00000010;
-    /** File was opened */
+    /** Event type: A file or directory was opened */
     public static final int OPEN = 0x00000020;
-    /** File was moved from X */
+    /** Event type: A file or subdirectory was moved from the monitored directory */
     public static final int MOVED_FROM = 0x00000040;
-    /** File was moved to Y */
+    /** Event type: A file or subdirectory was moved to the monitored directory */
     public static final int MOVED_TO = 0x00000080;
-    /** Subfile was created */
+    /** Event type: A new file or subdirectory was created under the monitored directory */
     public static final int CREATE = 0x00000100;
-    /** Subfile was deleted */
+    /** Event type: A file was deleted from the monitored directory */
     public static final int DELETE = 0x00000200;
-    /** Self was deleted */
+    /** Event type: The monitored file or directory was deleted; monitoring effectively stops */
     public static final int DELETE_SELF = 0x00000400;
-    /** Self was moved */
+    /** Event type: The monitored file or directory was moved; monitoring continues */
     public static final int MOVE_SELF = 0x00000800;
 
-    public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE 
+    /** Event mask: All valid event types, combined */
+    public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
             | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
             | DELETE_SELF | MOVE_SELF;
 
@@ -128,10 +147,21 @@
     private Integer m_descriptor;
     private int m_mask;
 
+    /**
+     * Equivalent to FileObserver(path, FileObserver.ALL_EVENTS).
+     */
     public FileObserver(String path) {
         this(path, ALL_EVENTS);
     }
 
+    /**
+     * Create a new file observer for a certain file or directory.
+     * Monitoring does not start on creation!  You must call
+     * {@link #startWatching()} before you will receive events.
+     *
+     * @param path The file or directory to monitor
+     * @param mask The event or events (added together) to watch for
+     */
     public FileObserver(String path, int mask) {
         m_path = path;
         m_mask = mask;
@@ -142,12 +172,22 @@
         stopWatching();
     }
 
+    /**
+     * Start watching for events.  The monitored file or directory must exist at
+     * this time, or else no events will be reported (even if it appears later).
+     * If monitoring is already started, this call has no effect.
+     */
     public void startWatching() {
         if (m_descriptor < 0) {
             m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
         }
     }
 
+    /**
+     * Stop watching for events.  Some events may be in process, so events
+     * may continue to be reported even after this method completes.  If
+     * monitoring is already stopped, this call has no effect.
+     */
     public void stopWatching() {
         if (m_descriptor >= 0) {
             s_observerThread.stopWatching(m_descriptor);
@@ -155,5 +195,19 @@
         }
     }
 
+    /**
+     * The event handler, which must be implemented by subclasses.
+     *
+     * <p class="note">This method is invoked on a special FileObserver thread.
+     * It runs independently of any threads, so take care to use appropriate
+     * synchronization!  Consider using {@link Handler#post(Runnable)} to shift
+     * event handling work to the main thread to avoid concurrency problems.</p>
+     *
+     * <p>Event handlers must not throw exceptions.</p>
+     *
+     * @param event The type of event which happened
+     * @param path The path, relative to the main monitored file or directory,
+     *     of the file or directory which triggered the event
+     */
     public abstract void onEvent(int event, String path);
 }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 3b8f295..2f7720a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -30,9 +30,10 @@
 import android.text.style.ParagraphStyle;
 import android.text.style.ReplacementSpan;
 import android.text.style.TabStopSpan;
+import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
 import android.view.KeyEvent;
 
-import junit.framework.Assert;
+import java.util.Arrays;
 
 /**
  * A base class that manages text layout in visual elements on
@@ -42,7 +43,6 @@
  * For text that will not change, use a {@link StaticLayout}.
  */
 public abstract class Layout {
-    private static final boolean DEBUG = false;
     private static final ParagraphStyle[] NO_PARA_SPANS =
         ArrayUtils.emptyArray(ParagraphStyle.class);
 
@@ -87,8 +87,7 @@
                 next = end;
 
             // note, omits trailing paragraph char
-            float w = measurePara(paint, workPaint,
-                                  source, i, next, true, null);
+            float w = measurePara(paint, workPaint, source, i, next);
 
             if (w > need)
                 need = w;
@@ -186,7 +185,6 @@
             dbottom = sTempRect.bottom;
         }
 
-
         int top = 0;
         int bottom = getLineTop(getLineCount());
 
@@ -209,13 +207,15 @@
         boolean spannedText = mSpannedText;
 
         ParagraphStyle[] spans = NO_PARA_SPANS;
-        int spanend = 0;
+        int spanEnd = 0;
         int textLength = 0;
 
         // First, draw LineBackgroundSpans.
-        // LineBackgroundSpans know nothing about the alignment or direction of
-        // the layout or line.  XXX: Should they?
+        // LineBackgroundSpans know nothing about the alignment, margins, or 
+        // direction of the layout or line.  XXX: Should they?
+        // They are evaluated at each line.
         if (spannedText) {
+            Spanned sp = (Spanned) buf;
             textLength = buf.length();
             for (int i = first; i <= last; i++) {
                 int start = previousLineEnd;
@@ -227,12 +227,14 @@
                 previousLineBottom = lbottom;
                 int lbaseline = lbottom - getLineDescent(i);
 
-                if (start >= spanend) {
-                   Spanned sp = (Spanned) buf;
-                   spanend = sp.nextSpanTransition(start, textLength,
-                                                   LineBackgroundSpan.class);
-                   spans = sp.getSpans(start, spanend,
-                                       LineBackgroundSpan.class);
+                if (start >= spanEnd) {
+                    // These should be infrequent, so we'll use this so that
+                    // we don't have to check as often.
+                    spanEnd = sp.nextSpanTransition(start, textLength, 
+                            LineBackgroundSpan.class);
+                    // All LineBackgroundSpans on a line contribute to its
+                    // background.
+                   spans = sp.getSpans(start, end, LineBackgroundSpan.class);
                 }
 
                 for (int n = 0; n < spans.length; n++) {
@@ -245,7 +247,7 @@
                 }
             }
             // reset to their original values
-            spanend = 0;
+            spanEnd = 0;
             previousLineBottom = getLineTop(first);
             previousLineEnd = getLineStart(first);
             spans = NO_PARA_SPANS;
@@ -266,8 +268,11 @@
         }
 
         Alignment align = mAlignment;
+        TabStops tabStops = null;
+        boolean tabStopsIsInitialized = false;
 
         TextLine tl = TextLine.obtain();
+
         // Next draw the lines, one at a time.
         // the baseline is the top of the following line minus the current
         // line's descent.
@@ -282,18 +287,29 @@
             previousLineBottom = lbottom;
             int lbaseline = lbottom - getLineDescent(i);
 
-            boolean isFirstParaLine = false;
+            int dir = getParagraphDirection(i);
+            int left = 0;
+            int right = mWidth;
+
             if (spannedText) {
-                if (start == 0 || buf.charAt(start - 1) == '\n') {
-                    isFirstParaLine = true;
-                }
-                // New batch of paragraph styles, compute the alignment.
-                // Last alignment style wins.
-                if (start >= spanend) {
-                    Spanned sp = (Spanned) buf;
-                    spanend = sp.nextSpanTransition(start, textLength,
+                Spanned sp = (Spanned) buf;
+                boolean isFirstParaLine = (start == 0 ||
+                        buf.charAt(start - 1) == '\n');
+                
+                // New batch of paragraph styles, collect into spans array.
+                // Compute the alignment, last alignment style wins.
+                // Reset tabStops, we'll rebuild if we encounter a line with
+                // tabs.
+                // We expect paragraph spans to be relatively infrequent, use
+                // spanEnd so that we can check less frequently.  Since
+                // paragraph styles ought to apply to entire paragraphs, we can
+                // just collect the ones present at the start of the paragraph.
+                // If spanEnd is before the end of the paragraph, that's not
+                // our problem.
+                if (start >= spanEnd && (i == first || isFirstParaLine)) {
+                    spanEnd = sp.nextSpanTransition(start, textLength,
                                                     ParagraphStyle.class);
-                    spans = sp.getSpans(start, spanend, ParagraphStyle.class);
+                    spans = sp.getSpans(start, spanEnd, ParagraphStyle.class);
 
                     align = mAlignment;
                     for (int n = spans.length-1; n >= 0; n--) {
@@ -302,45 +318,49 @@
                             break;
                         }
                     }
+                    
+                    tabStopsIsInitialized = false;
                 }
-            }
 
-            int dir = getParagraphDirection(i);
-            int left = 0;
-            int right = mWidth;
-
-            // Draw all leading margin spans.  Adjust left or right according
-            // to the paragraph direction of the line.
-            if (spannedText) {
+                // Draw all leading margin spans.  Adjust left or right according
+                // to the paragraph direction of the line.
                 final int length = spans.length;
                 for (int n = 0; n < length; n++) {
                     if (spans[n] instanceof LeadingMarginSpan) {
                         LeadingMarginSpan margin = (LeadingMarginSpan) spans[n];
+                        boolean useFirstLineMargin = isFirstParaLine;
+                        if (margin instanceof LeadingMarginSpan2) {
+                            int count = ((LeadingMarginSpan2) margin).getLeadingMarginLineCount();
+                            int startLine = getLineForOffset(sp.getSpanStart(margin));
+                            useFirstLineMargin = i < startLine + count;
+                        }
 
                         if (dir == DIR_RIGHT_TO_LEFT) {
                             margin.drawLeadingMargin(c, paint, right, dir, ltop,
                                                      lbaseline, lbottom, buf,
                                                      start, end, isFirstParaLine, this);
-
-                            right -= margin.getLeadingMargin(isFirstParaLine);
+                            right -= margin.getLeadingMargin(useFirstLineMargin);
                         } else {
                             margin.drawLeadingMargin(c, paint, left, dir, ltop,
                                                      lbaseline, lbottom, buf,
                                                      start, end, isFirstParaLine, this);
-
-                            boolean useMargin = isFirstParaLine;
-                            if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) {
-                                int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount();
-                                useMargin = count > i;
-                            }
-                            left += margin.getLeadingMargin(useMargin);
+                            left += margin.getLeadingMargin(useFirstLineMargin);
                         }
                     }
                 }
             }
 
-            // Adjust the point at which to start rendering depending on the
-            // alignment of the paragraph.
+            boolean hasTabOrEmoji = getLineContainsTab(i);
+            // Can't tell if we have tabs for sure, currently
+            if (hasTabOrEmoji && !tabStopsIsInitialized) {
+                if (tabStops == null) {
+                    tabStops = new TabStops(TAB_INCREMENT, spans);
+                } else {
+                    tabStops.reset(TAB_INCREMENT, spans);
+                }
+                tabStopsIsInitialized = true;
+            }
+
             int x;
             if (align == Alignment.ALIGN_NORMAL) {
                 if (dir == DIR_LEFT_TO_RIGHT) {
@@ -349,44 +369,83 @@
                     x = right;
                 }
             } else {
-                int max = (int)getLineMax(i, spans, false);
+                int max = (int)getLineExtent(i, tabStops, false);
                 if (align == Alignment.ALIGN_OPPOSITE) {
-                    if (dir == DIR_RIGHT_TO_LEFT) {
-                        x = left + max;
-                    } else {
+                    if (dir == DIR_LEFT_TO_RIGHT) {
                         x = right - max;
-                    }
-                } else {
-                    // Alignment.ALIGN_CENTER
-                    max = max & ~1;
-                    int half = (right - left - max) >> 1;
-                    if (dir == DIR_RIGHT_TO_LEFT) {
-                        x = right - half;
                     } else {
-                        x = left + half;
+                        x = left - max;
                     }
+                } else { // Alignment.ALIGN_CENTER
+                    max = max & ~1;
+                    x = (right + left - max) >> 1;
                 }
             }
 
             Directions directions = getLineDirections(i);
-            boolean hasTab = getLineContainsTab(i);
             if (directions == DIRS_ALL_LEFT_TO_RIGHT &&
-                    !spannedText && !hasTab) {
-                if (DEBUG) {
-                    Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT);
-                    Assert.assertNotNull(c);
-                }
+                    !spannedText && !hasTabOrEmoji) {
                 // XXX: assumes there's nothing additional to be done
                 c.drawText(buf, start, end, x, lbaseline, paint);
             } else {
-                tl.set(paint, buf, start, end, dir, directions, hasTab, spans);
+                tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops);
                 tl.draw(c, x, ltop, lbaseline, lbottom);
             }
         }
+
         TextLine.recycle(tl);
     }
 
     /**
+     * Return the start position of the line, given the left and right bounds
+     * of the margins.
+     * 
+     * @param line the line index
+     * @param left the left bounds (0, or leading margin if ltr para)
+     * @param right the right bounds (width, minus leading margin if rtl para)
+     * @return the start position of the line (to right of line if rtl para)
+     */
+    private int getLineStartPos(int line, int left, int right) {
+        // Adjust the point at which to start rendering depending on the
+        // alignment of the paragraph.
+        Alignment align = getParagraphAlignment(line);
+        int dir = getParagraphDirection(line);
+
+        int x;
+        if (align == Alignment.ALIGN_NORMAL) {
+            if (dir == DIR_LEFT_TO_RIGHT) {
+                x = left;
+            } else {
+                x = right;
+            }
+        } else {
+            TabStops tabStops = null;
+            if (mSpannedText && getLineContainsTab(line)) {
+                Spanned spanned = (Spanned) mText;
+                int start = getLineStart(line);
+                int spanEnd = spanned.nextSpanTransition(start, spanned.length(),
+                        TabStopSpan.class);
+                TabStopSpan[] tabSpans = spanned.getSpans(start, spanEnd, TabStopSpan.class);
+                if (tabSpans.length > 0) {
+                    tabStops = new TabStops(TAB_INCREMENT, tabSpans);
+                }
+            }
+            int max = (int)getLineExtent(line, tabStops, false);
+            if (align == Alignment.ALIGN_OPPOSITE) {
+                if (dir == DIR_LEFT_TO_RIGHT) {
+                    x = right - max;
+                } else {
+                    x = left - max;
+                }
+            } else { // Alignment.ALIGN_CENTER
+                max = max & ~1;
+                x = (left + right - max) >> 1;
+            }
+        }
+        return x;
+    }
+
+    /**
      * Return the text that is displayed by this Layout.
      */
     public final CharSequence getText() {
@@ -647,45 +706,28 @@
         int start = getLineStart(line);
         int end = getLineEnd(line);
         int dir = getParagraphDirection(line);
-        boolean tab = getLineContainsTab(line);
+        boolean hasTabOrEmoji = getLineContainsTab(line);
         Directions directions = getLineDirections(line);
 
-        TabStopSpan[] tabs = null;
-        if (tab && mText instanceof Spanned) {
-            tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+        TabStops tabStops = null;
+        if (hasTabOrEmoji && mText instanceof Spanned) {
+            // Just checking this line should be good enough, tabs should be
+            // consistent across all lines in a paragraph.
+            TabStopSpan[] tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+            if (tabs.length > 0) {
+                tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+            }
         }
 
         TextLine tl = TextLine.obtain();
-        tl.set(mPaint, mText, start, end, dir, directions, tab, tabs);
+        tl.set(mPaint, mText, start, end, dir, directions, hasTabOrEmoji, tabStops);
         float wid = tl.measure(offset - start, trailing, null);
         TextLine.recycle(tl);
 
-        Alignment align = getParagraphAlignment(line);
         int left = getParagraphLeft(line);
         int right = getParagraphRight(line);
 
-        if (align == Alignment.ALIGN_NORMAL) {
-            if (dir == DIR_RIGHT_TO_LEFT)
-                return right + wid;
-            else
-                return left + wid;
-        }
-
-        float max = getLineMax(line);
-
-        if (align == Alignment.ALIGN_OPPOSITE) {
-            if (dir == DIR_RIGHT_TO_LEFT)
-                return left + max + wid;
-            else
-                return right - max + wid;
-        } else { /* align == Alignment.ALIGN_CENTER */
-            int imax = ((int) max) & ~1;
-
-            if (dir == DIR_RIGHT_TO_LEFT)
-                return right - (((right - left) - imax) / 2) + wid;
-            else
-                return left + ((right - left) - imax) / 2 + wid;
-        }
+        return getLineStartPos(line, left, right) + wid;
     }
 
     /**
@@ -743,29 +785,73 @@
     }
 
     /**
-     * Gets the horizontal extent of the specified line, excluding
-     * trailing whitespace.
+     * Gets the unsigned horizontal extent of the specified line, including 
+     * leading margin indent, but excluding trailing whitespace.
      */
     public float getLineMax(int line) {
-        return getLineMax(line, null, false);
+        float margin = getParagraphLeadingMargin(line);
+        float signedExtent = getLineExtent(line, false);
+        return margin + signedExtent >= 0 ? signedExtent : -signedExtent;
     }
 
     /**
-     * Gets the horizontal extent of the specified line, including
-     * trailing whitespace.
+     * Gets the unsigned horizontal extent of the specified line, including
+     * leading margin indent and trailing whitespace.
      */
     public float getLineWidth(int line) {
-        return getLineMax(line, null, true);
+        float margin = getParagraphLeadingMargin(line);
+        float signedExtent = getLineExtent(line, true);
+        return margin + signedExtent >= 0 ? signedExtent : -signedExtent;
     }
 
-    private float getLineMax(int line, Object[] tabs, boolean full) {
+    /**
+     * Like {@link #getLineExtent(int,TabStops,boolean)} but determines the
+     * tab stops instead of using the ones passed in.
+     * @param line the index of the line
+     * @param full whether to include trailing whitespace
+     * @return the extent of the line
+     */
+    private float getLineExtent(int line, boolean full) {
         int start = getLineStart(line);
         int end = full ? getLineEnd(line) : getLineVisibleEnd(line);
-        boolean hasTabs = getLineContainsTab(line);
+
+        boolean hasTabsOrEmoji = getLineContainsTab(line);
+        TabStops tabStops = null;
+        if (hasTabsOrEmoji && mText instanceof Spanned) {
+            // Just checking this line should be good enough, tabs should be
+            // consistent across all lines in a paragraph.
+            TabStopSpan[] tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+            if (tabs.length > 0) {
+                tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+            }
+        }
         Directions directions = getLineDirections(line);
+        int dir = getParagraphDirection(line);
 
         TextLine tl = TextLine.obtain();
-        tl.set(mPaint, mText, start, end, 1, directions, hasTabs, tabs);
+        tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops);
+        float width = tl.metrics(null);
+        TextLine.recycle(tl);
+        return width;
+    }
+
+    /**
+     * Returns the signed horizontal extent of the specified line, excluding
+     * leading margin.  If full is false, excludes trailing whitespace.
+     * @param line the index of the line
+     * @param tabStops the tab stops, can be null if we know they're not used.
+     * @param full whether to include trailing whitespace
+     * @return the extent of the text on this line
+     */
+    private float getLineExtent(int line, TabStops tabStops, boolean full) {
+        int start = getLineStart(line);
+        int end = full ? getLineEnd(line) : getLineVisibleEnd(line);
+        boolean hasTabsOrEmoji = getLineContainsTab(line);
+        Directions directions = getLineDirections(line);
+        int dir = getParagraphDirection(line);
+
+        TextLine tl = TextLine.obtain();
+        tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops);
         float width = tl.metrics(null);
         TextLine.recycle(tl);
         return width;
@@ -910,10 +996,6 @@
     }
 
     private int getLineVisibleEnd(int line, int start, int end) {
-        if (DEBUG) {
-            Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end);
-        }
-
         CharSequence text = mText;
         char ch;
         if (line == getLineCount() - 1) {
@@ -1243,84 +1325,107 @@
      * Get the left edge of the specified paragraph, inset by left margins.
      */
     public final int getParagraphLeft(int line) {
-        int dir = getParagraphDirection(line);
-
         int left = 0;
-
-        boolean par = false;
-        int off = getLineStart(line);
-        if (off == 0 || mText.charAt(off - 1) == '\n')
-            par = true;
-
-        if (dir == DIR_LEFT_TO_RIGHT) {
-            if (mSpannedText) {
-                Spanned sp = (Spanned) mText;
-                LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line),
-                                                        getLineEnd(line),
-                                                        LeadingMarginSpan.class);
-
-                for (int i = 0; i < spans.length; i++) {
-                    boolean margin = par;
-                    LeadingMarginSpan span = spans[i];
-                    if (span instanceof LeadingMarginSpan.LeadingMarginSpan2) {
-                        int count = ((LeadingMarginSpan.LeadingMarginSpan2)span).getLeadingMarginLineCount();
-                        margin = count >= line;
-                    }
-                    left += span.getLeadingMargin(margin);
-                }
-            }
+        int dir = getParagraphDirection(line);
+        if (dir == DIR_RIGHT_TO_LEFT || !mSpannedText) {
+            return left; // leading margin has no impact, or no styles
         }
-
-        return left;
+        return getParagraphLeadingMargin(line);
     }
 
     /**
      * Get the right edge of the specified paragraph, inset by right margins.
      */
     public final int getParagraphRight(int line) {
-        int dir = getParagraphDirection(line);
-
         int right = mWidth;
+        int dir = getParagraphDirection(line);
+        if (dir == DIR_LEFT_TO_RIGHT || !mSpannedText) {
+            return right; // leading margin has no impact, or no styles
+        }
+        return right - getParagraphLeadingMargin(line);
+    }
 
-        boolean par = false;
-        int off = getLineStart(line);
-        if (off == 0 || mText.charAt(off - 1) == '\n')
-            par = true;
-
-
-        if (dir == DIR_RIGHT_TO_LEFT) {
-            if (mSpannedText) {
-                Spanned sp = (Spanned) mText;
-                LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line),
-                                                        getLineEnd(line),
-                                                        LeadingMarginSpan.class);
-
-                for (int i = 0; i < spans.length; i++) {
-                    right -= spans[i].getLeadingMargin(par);
-                }
+    /**
+     * Returns the effective leading margin (unsigned) for this line,
+     * taking into account LeadingMarginSpan and LeadingMarginSpan2.
+     * @param line the line index
+     * @return the leading margin of this line
+     */
+    private int getParagraphLeadingMargin(int line) {
+        if (!mSpannedText) {
+            return 0;
+        }
+        Spanned spanned = (Spanned) mText;
+        
+        int lineStart = getLineStart(line);
+        int lineEnd = getLineEnd(line);
+        int spanEnd = spanned.nextSpanTransition(lineStart, lineEnd, 
+                LeadingMarginSpan.class);
+        LeadingMarginSpan[] spans = spanned.getSpans(lineStart, spanEnd,
+                                                LeadingMarginSpan.class);
+        if (spans.length == 0) {
+            return 0; // no leading margin span;
+        }
+        
+        int margin = 0;
+        
+        boolean isFirstParaLine = lineStart == 0 || 
+            spanned.charAt(lineStart - 1) == '\n';
+        
+        for (int i = 0; i < spans.length; i++) {
+            LeadingMarginSpan span = spans[i];
+            boolean useFirstLineMargin = isFirstParaLine;
+            if (span instanceof LeadingMarginSpan2) {
+                int spStart = spanned.getSpanStart(span);
+                int spanLine = getLineForOffset(spStart);
+                int count = ((LeadingMarginSpan2)span).getLeadingMarginLineCount();
+                useFirstLineMargin = line < spanLine + count; 
             }
+            margin += span.getLeadingMargin(useFirstLineMargin);
         }
 
-        return right;
+        return margin;
     }
 
     /* package */
     static float measurePara(TextPaint paint, TextPaint workPaint,
-            CharSequence text, int start, int end, boolean hasTabs,
-            Object[] tabs) {
+            CharSequence text, int start, int end) {
 
         MeasuredText mt = MeasuredText.obtain();
         TextLine tl = TextLine.obtain();
         try {
             mt.setPara(text, start, end, DIR_REQUEST_LTR);
             Directions directions;
-            if (mt.mEasy){
+            int dir;
+            if (mt.mEasy) {
                 directions = DIRS_ALL_LEFT_TO_RIGHT;
+                dir = Layout.DIR_LEFT_TO_RIGHT;
             } else {
                 directions = AndroidBidi.directions(mt.mDir, mt.mLevels,
                     0, mt.mChars, 0, mt.mLen);
+                dir = mt.mDir;
             }
-            tl.set(paint, text, start, end, 1, directions, hasTabs, tabs);
+            char[] chars = mt.mChars;
+            int len = mt.mLen;
+            boolean hasTabs = false;
+            TabStops tabStops = null;
+            for (int i = 0; i < len; ++i) {
+                if (chars[i] == '\t') {
+                    hasTabs = true;
+                    if (text instanceof Spanned) {
+                        Spanned spanned = (Spanned) text;
+                        int spanEnd = spanned.nextSpanTransition(start, end, 
+                                TabStopSpan.class);
+                        TabStopSpan[] spans = spanned.getSpans(start, spanEnd, 
+                                TabStopSpan.class);
+                        if (spans.length > 0) {
+                            tabStops = new TabStops(TAB_INCREMENT, spans);
+                        }
+                    }
+                    break;
+                }
+            }
+            tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops);
             return tl.metrics(null);
         } finally {
             TextLine.recycle(tl);
@@ -1329,6 +1434,67 @@
     }
 
     /**
+     * @hide
+     */
+    /* package */ static class TabStops {
+        private int[] mStops;
+        private int mNumStops;
+        private int mIncrement;
+        
+        TabStops(int increment, Object[] spans) {
+            reset(increment, spans);
+        }
+        
+        void reset(int increment, Object[] spans) {
+            this.mIncrement = increment;
+
+            int ns = 0;
+            if (spans != null) {
+                int[] stops = this.mStops;
+                for (Object o : spans) {
+                    if (o instanceof TabStopSpan) {
+                        if (stops == null) {
+                            stops = new int[10];
+                        } else if (ns == stops.length) {
+                            int[] nstops = new int[ns * 2];
+                            for (int i = 0; i < ns; ++i) {
+                                nstops[i] = stops[i];
+                            }
+                            stops = nstops;
+                        }
+                        stops[ns++] = ((TabStopSpan) o).getTabStop();
+                    }
+                }
+                if (ns > 1) {
+                    Arrays.sort(stops, 0, ns);
+                }
+                if (stops != this.mStops) {
+                    this.mStops = stops;
+                }
+            }
+            this.mNumStops = ns;
+        }
+        
+        float nextTab(float h) {
+            int ns = this.mNumStops;
+            if (ns > 0) {
+                int[] stops = this.mStops;
+                for (int i = 0; i < ns; ++i) {
+                    int stop = stops[i];
+                    if (stop > h) {
+                        return stop;
+                    }
+                }
+            }
+            return nextDefaultStop(h, mIncrement);
+        }
+
+        public static float nextDefaultStop(float h, int inc) {
+            return ((int) ((h + inc) / inc)) * inc;
+        }
+    }
+    
+    /**
      * Returns the position of the next tab stop after h on the line.
      *
      * @param text the text
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 0c6c545..1646b9e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -23,6 +23,8 @@
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LineHeightSpan;
 import android.text.style.MetricAffectingSpan;
+import android.text.style.TabStopSpan;
+import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
 
 /**
  * StaticLayout is a Layout for text that will not be edited after it
@@ -146,7 +148,7 @@
                 paraEnd++;
             int paraLen = paraEnd - paraStart;
 
-            int firstWidthLineCount = 1;
+            int firstWidthLineLimit = mLineCount + 1;
             int firstwidth = outerwidth;
             int restwidth = outerwidth;
 
@@ -159,10 +161,16 @@
                     LeadingMarginSpan lms = sp[i];
                     firstwidth -= sp[i].getLeadingMargin(true);
                     restwidth -= sp[i].getLeadingMargin(false);
-                    if (lms instanceof LeadingMarginSpan.LeadingMarginSpan2) {
-                        firstWidthLineCount =
-                            ((LeadingMarginSpan.LeadingMarginSpan2)lms)
-                            .getLeadingMarginLineCount();
+                    
+                    // LeadingMarginSpan2 is odd.  The count affects all
+                    // leading margin spans, not just this particular one,
+                    // and start from the top of the span, not the top of the
+                    // paragraph.
+                    if (lms instanceof LeadingMarginSpan2) {
+                        LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
+                        int lmsFirstLine = getLineForOffset(spanned.getSpanStart(lms2));
+                        firstWidthLineLimit = lmsFirstLine + 
+                            lms2.getLeadingMarginLineCount();
                     }
                 }
 
@@ -214,28 +222,34 @@
             float fitwidth = w;
             int fitascent = 0, fitdescent = 0, fittop = 0, fitbottom = 0;
 
-            boolean tab = false;
+            boolean hasTabOrEmoji = false;
+            boolean hasTab = false;
+            TabStops tabStops = null;
 
-            int spanEnd;
-            for (int spanStart = paraStart; spanStart < paraEnd; spanStart = spanEnd) {
-                if (spanned == null)
-                    spanEnd = paraEnd;
-                else
-                    spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
-                            MetricAffectingSpan.class);
+            for (int spanStart = paraStart, spanEnd = spanStart, nextSpanStart;
+                    spanStart < paraEnd; spanStart = nextSpanStart) {
 
-                int spanLen = spanEnd - spanStart;
+                if (spanStart == spanEnd) {
+                    if (spanned == null)
+                        spanEnd = paraEnd;
+                    else
+                        spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
+                                MetricAffectingSpan.class);
+
+                    int spanLen = spanEnd - spanStart;
+                    if (spanned == null) {
+                        measured.addStyleRun(paint, spanLen, fm);
+                    } else {
+                        MetricAffectingSpan[] spans =
+                            spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
+                        measured.addStyleRun(paint, spans, spanLen, fm);
+                    }
+                }
+
+                nextSpanStart = spanEnd;
                 int startInPara = spanStart - paraStart;
                 int endInPara = spanEnd - paraStart;
 
-                if (spanned == null) {
-                    measured.addStyleRun(paint, spanLen, fm);
-                } else {
-                    MetricAffectingSpan[] spans =
-                        spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
-                    measured.addStyleRun(paint, spans, spanLen, fm);
-                }
-
                 int fmtop = fm.top;
                 int fmbottom = fm.bottom;
                 int fmascent = fm.ascent;
@@ -248,8 +262,21 @@
                     if (c == '\n') {
                         ;
                     } else if (c == '\t') {
-                        w = Layout.nextTab(sub, paraStart, paraEnd, w, null);
-                        tab = true;
+                        if (hasTab == false) {
+                            hasTab = true;
+                            hasTabOrEmoji = true;
+                            // First tab this para, check for tabstops
+                            TabStopSpan[] spans = spanned.getSpans(paraStart, 
+                                    paraEnd, TabStopSpan.class);
+                            if (spans.length > 0) {
+                                tabStops = new TabStops(TAB_INCREMENT, spans);
+                            }
+                        }
+                        if (tabStops != null) {
+                            w = tabStops.nextTab(w);
+                        } else {
+                            w = TabStops.nextDefaultStop(w, TAB_INCREMENT);
+                        }
                     } else if (c >= 0xD800 && c <= 0xDFFF && j + 1 < spanEnd) {
                         int emoji = Character.codePointAt(chs, j - paraStart);
 
@@ -271,7 +298,7 @@
                                             bm.getHeight();
 
                                 w += wid;
-                                tab = true;
+                                hasTabOrEmoji = true;
                                 j++;
                             } else {
                                 w += widths[j - paraStart];
@@ -347,7 +374,7 @@
                                     okascent, okdescent, oktop, okbottom,
                                     v,
                                     spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, tab,
+                                    choosehtv, fm, hasTabOrEmoji,
                                     needMultiply, paraStart, chdirs, dir, easy,
                                     ok == bufend, includepad, trackpad,
                                     chs, widths, here - paraStart,
@@ -383,7 +410,7 @@
                                     okascent, okdescent, oktop, okbottom,
                                     v,
                                     spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, tab,
+                                    choosehtv, fm, hasTabOrEmoji,
                                     needMultiply, paraStart, chdirs, dir, easy,
                                     ok == bufend, includepad, trackpad,
                                     chs, widths, here - paraStart,
@@ -399,7 +426,7 @@
                                     fittop, fitbottom,
                                     v,
                                     spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, tab,
+                                    choosehtv, fm, hasTabOrEmoji,
                                     needMultiply, paraStart, chdirs, dir, easy,
                                     fit == bufend, includepad, trackpad,
                                     chs, widths, here - paraStart,
@@ -420,7 +447,7 @@
                                     fm.top, fm.bottom,
                                     v,
                                     spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, tab,
+                                    choosehtv, fm, hasTabOrEmoji,
                                     needMultiply, paraStart, chdirs, dir, easy,
                                     here + 1 == bufend, includepad,
                                     trackpad,
@@ -432,7 +459,10 @@
                         }
 
                         if (here < spanStart) {
-                            j = spanEnd = here; // must remeasure
+                            // didn't output all the text for this span
+                            // we've measured the raw widths, though, so
+                            // just reset the start point
+                            j = nextSpanStart = here;
                         } else {
                             j = here - 1;    // continue looping
                         }
@@ -442,7 +472,7 @@
                         fitascent = fitdescent = fittop = fitbottom = 0;
                         okascent = okdescent = oktop = okbottom = 0;
 
-                        if (--firstWidthLineCount <= 0) {
+                        if (--firstWidthLineLimit <= 0) {
                             width = restwidth;
                         }
                     }
@@ -466,7 +496,7 @@
                         fittop, fitbottom,
                         v,
                         spacingmult, spacingadd, chooseht,
-                        choosehtv, fm, tab,
+                        choosehtv, fm, hasTabOrEmoji,
                         needMultiply, paraStart, chdirs, dir, easy,
                         paraEnd == bufend, includepad, trackpad,
                         chs, widths, here - paraStart,
@@ -606,7 +636,7 @@
                       int above, int below, int top, int bottom, int v,
                       float spacingmult, float spacingadd,
                       LineHeightSpan[] chooseht, int[] choosehtv,
-                      Paint.FontMetricsInt fm, boolean tab,
+                      Paint.FontMetricsInt fm, boolean hasTabOrEmoji,
                       boolean needMultiply, int pstart, byte[] chdirs,
                       int dir, boolean easy, boolean last,
                       boolean includepad, boolean trackpad,
@@ -693,7 +723,7 @@
         lines[off + mColumns + START] = end;
         lines[off + mColumns + TOP] = v;
 
-        if (tab)
+        if (hasTabOrEmoji)
             lines[off + TAB] |= TAB_MASK;
 
         lines[off + DIR] |= dir << DIR_SHIFT;
@@ -907,7 +937,7 @@
     private static final int DIR_SHIFT  = 30;
     private static final int TAB_MASK   = 0x20000000;
 
-    private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
+    private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
 
     /*
      * This is reused across calls to generate()
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index fae3fc3..bd410c8 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -25,10 +25,10 @@
 import android.graphics.Paint.FontMetricsInt;
 import android.icu.text.ArabicShaping;
 import android.text.Layout.Directions;
+import android.text.Layout.TabStops;
 import android.text.style.CharacterStyle;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.ReplacementSpan;
-import android.text.style.TabStopSpan;
 import android.util.Log;
 
 /**
@@ -51,7 +51,7 @@
     private int mDir;
     private Directions mDirections;
     private boolean mHasTabs;
-    private TabStopSpan[] mTabs;
+    private TabStops mTabs;
 
     private char[] mChars;
     private boolean mCharsValid;
@@ -117,11 +117,10 @@
      * @param dir the paragraph direction of this line
      * @param directions the directions information of this line
      * @param hasTabs true if the line might contain tabs or emoji
-     * @param spans array of paragraph-level spans, of which only TabStopSpans
-     * are used.  Can be null.
+     * @param tabStops the tabStops. Can be null.
      */
     void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
-            Directions directions, boolean hasTabs, Object[] spans) {
+            Directions directions, boolean hasTabs, TabStops tabStops) {
         mPaint = paint;
         mText = text;
         mStart = start;
@@ -148,38 +147,8 @@
                 mChars = new char[ArrayUtils.idealCharArraySize(mLen)];
             }
             TextUtils.getChars(text, start, limit, mChars, 0);
-
-            if (hasTabs) {
-                TabStopSpan[] tabs = mTabs;
-                int tabLen = 0;
-                if (mSpanned != null && spans == null) {
-                    TabStopSpan[] newTabs = mSpanned.getSpans(start, limit,
-                            TabStopSpan.class);
-                    if (tabs == null || tabs.length < newTabs.length) {
-                        tabs = newTabs;
-                    } else {
-                        for (int i = 0; i < newTabs.length; ++i) {
-                            tabs[i] = newTabs[i];
-                        }
-                    }
-                    tabLen = newTabs.length;
-                } else if (spans != null) {
-                    if (tabs == null || tabs.length < spans.length) {
-                        tabs = new TabStopSpan[spans.length];
-                    }
-                    for (int i = 0; i < spans.length; ++i) {
-                        if (spans[i] instanceof TabStopSpan) {
-                            tabs[tabLen++] = (TabStopSpan) spans[i];
-                        }
-                    }
-                }
-
-                if (tabs != null && tabLen < tabs.length){
-                    tabs[tabLen] = null;
-                }
-                mTabs = tabs;
-            }
         }
+        mTabs = tabStops;
     }
 
     /**
@@ -993,23 +962,10 @@
      * @return the (unsigned) tab position after this offset
      */
     float nextTab(float h) {
-        float nh = Float.MAX_VALUE;
-        boolean alltabs = false;
-
-        if (mHasTabs && mTabs != null) {
-            TabStopSpan[] tabs = mTabs;
-            for (int i = 0; i < tabs.length && tabs[i] != null; ++i) {
-                int where = tabs[i].getTabStop();
-                if (where < nh && where > h) {
-                    nh = where;
-                }
-            }
-            if (nh != Float.MAX_VALUE) {
-                return nh;
-            }
+        if (mTabs != null) {
+            return mTabs.nextTab(h);
         }
-
-        return ((int) ((h + TAB_INCREMENT) / TAB_INCREMENT)) * TAB_INCREMENT;
+        return TabStops.nextDefaultStop(h, TAB_INCREMENT);
     }
 
     private static final int TAB_INCREMENT = 20;
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index 42ad10e..c30db20 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -18,13 +18,12 @@
 
 import android.text.Layout;
 import android.text.NoCopySpan;
-import android.text.Layout.Alignment;
 import android.text.Spannable;
-import android.util.Log;
+import android.text.Layout.Alignment;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.widget.TextView;
-import android.view.KeyEvent;
 
 public class Touch {
     private Touch() { }
@@ -45,6 +44,7 @@
         int left = Integer.MAX_VALUE;
         int right = 0;
         Alignment a = null;
+        boolean ltr = true;
 
         for (int i = top; i <= bottom; i++) {
             left = (int) Math.min(left, layout.getLineLeft(i));
@@ -52,6 +52,7 @@
 
             if (a == null) {
                 a = layout.getParagraphAlignment(i);
+                ltr = layout.getParagraphDirection(i) > 0;
             }
         }
 
@@ -59,10 +60,12 @@
         int width = widget.getWidth();
         int diff = 0;
 
+        // align_opposite does NOT mean align_right, we need the paragraph
+        // direction to resolve it to left or right
         if (right - left < width - padding) {
             if (a == Alignment.ALIGN_CENTER) {
                 diff = (width - padding - (right - left)) / 2;
-            } else if (a == Alignment.ALIGN_OPPOSITE) {
+            } else if (ltr == (a == Alignment.ALIGN_OPPOSITE)) {
                 diff = width - padding - (right - left);
             }
         }
diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java
index 952d833..69cf93c 100644
--- a/core/java/android/text/util/Rfc822Tokenizer.java
+++ b/core/java/android/text/util/Rfc822Tokenizer.java
@@ -84,8 +84,10 @@
                     if (c == '"') {
                         i++;
                         break;
-                    } else if (c == '\\' && i + 1 < cursor) {
-                        name.append(text.charAt(i + 1));
+                    } else if (c == '\\') {
+                        if (i + 1 < cursor) {
+                            name.append(text.charAt(i + 1));
+                        }
                         i += 2;
                     } else {
                         name.append(c);
@@ -110,8 +112,10 @@
                         comment.append(c);
                         level++;
                         i++;
-                    } else if (c == '\\' && i + 1 < cursor) {
-                        comment.append(text.charAt(i + 1));
+                    } else if (c == '\\') {
+                        if (i + 1 < cursor) {
+                            comment.append(text.charAt(i + 1));
+                        }
                         i += 2;
                     } else {
                         comment.append(c);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index d648e96..eefbf7a 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -255,17 +255,19 @@
     }
 
     static private MotionEvent obtain() {
+        final MotionEvent ev;
         synchronized (gRecyclerLock) {
             if (gRecyclerTop == null) {
                 return new MotionEvent();
             }
-            MotionEvent ev = gRecyclerTop;
+            ev = gRecyclerTop;
             gRecyclerTop = ev.mNext;
             gRecyclerUsed--;
-            ev.mRecycledLocation = null;
-            ev.mRecycled = false;
-            return ev;
         }
+        ev.mRecycledLocation = null;
+        ev.mRecycled = false;
+        ev.mNext = null;
+        return ev;
     }
 
     /**
@@ -620,11 +622,14 @@
                 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
             }
             mRecycledLocation = new RuntimeException("Last recycled here");
-        } else if (mRecycled) {
-            throw new RuntimeException(toString() + " recycled twice!");
+            //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
+        } else {
+            if (mRecycled) {
+                throw new RuntimeException(toString() + " recycled twice!");
+            }
+            mRecycled = true;
         }
 
-        //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
         synchronized (gRecyclerLock) {
             if (gRecyclerUsed < MAX_RECYCLED) {
                 gRecyclerUsed++;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 527b4f4..3461cbf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8594,13 +8594,12 @@
         if (mAttachInfo == null) {
             return false;
         }
-        if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
+        if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
                 && !isHapticFeedbackEnabled()) {
             return false;
         }
-        return mAttachInfo.mRootCallbacks.performHapticFeedback(
-                feedbackConstant,
-                (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
+        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
+                (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
     }
 
     /**
@@ -8671,8 +8670,7 @@
                 ViewConfiguration.getLongPressTimeout() - delayOffset);
     }
 
-    private static int[] stateSetUnion(final int[] stateSet1,
-                                       final int[] stateSet2) {
+    private static int[] stateSetUnion(final int[] stateSet1, final int[] stateSet2) {
         final int stateSet1Length = stateSet1.length;
         final int stateSet2Length = stateSet2.length;
         final int[] newSet = new int[stateSet1Length + stateSet2Length];
@@ -8710,7 +8708,7 @@
         LayoutInflater factory = LayoutInflater.from(context);
         return factory.inflate(resource, root);
     }
-
+    
     /**
      * A MeasureSpec encapsulates the layout requirements passed from parent to child.
      * Each MeasureSpec represents a requirement for either the width or the height.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9329d94..1fc0251 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1566,7 +1566,8 @@
 
         boolean scalingRequired = false;
         Bitmap cache = null;
-        if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+        if (canvas.getGL() == null &&
+                (flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
                 (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
             cache = child.getDrawingCache(true);
             if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index aa124e6..15c6910 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.content.pm.ApplicationInfo;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
@@ -33,7 +34,6 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.EventLog;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
@@ -52,7 +52,6 @@
 import android.media.AudioManager;
 
 import java.lang.ref.WeakReference;
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -68,14 +67,12 @@
  *
  * {@hide}
  */
-@SuppressWarnings({"EmptyCatchBlock"})
-public final class ViewRoot extends Handler implements ViewParent,
-        View.AttachInfo.Callbacks {
+@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
+public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks {
     private static final String TAG = "ViewRoot";
     private static final boolean DBG = false;
     private static final boolean SHOW_FPS = false;
-    @SuppressWarnings({"ConstantConditionalExpression"})
-    private static final boolean LOCAL_LOGV = false ? Config.LOGD : Config.LOGV;
+    private static final boolean LOCAL_LOGV = false;
     /** @noinspection PointlessBooleanExpression*/
     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
@@ -202,14 +199,7 @@
     int mCurScrollY;
     Scroller mScroller;
 
-    EGL10 mEgl;
-    EGLDisplay mEglDisplay;
-    EGLContext mEglContext;
-    EGLSurface mEglSurface;
-    GL11 mGL;
-    Canvas mGlCanvas;
-    boolean mUseGL;
-    boolean mGlWanted;
+    HardwareRenderer mHwRenderer;
 
     final ViewConfiguration mViewConfiguration;
 
@@ -239,8 +229,10 @@
     public ViewRoot(Context context) {
         super();
 
-        if (MEASURE_LATENCY && lt == null) {
-            lt = new LatencyTimer(100, 1000);
+        if (MEASURE_LATENCY) {
+            if (lt == null) {
+                lt = new LatencyTimer(100, 1000);
+            }
         }
 
         // For debug only
@@ -270,6 +262,12 @@
         mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
         mViewConfiguration = ViewConfiguration.get(context);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
+
+        // Try to enable hardware acceleration if requested
+        if ((context.getApplicationInfo().flags &
+                ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+            mHwRenderer = new HardwareRenderer();
+        }
     }
 
     // For debug only
@@ -328,112 +326,6 @@
         return false;
     }
 
-    private void initializeGL() {
-        initializeGLInner();
-        int err = mEgl.eglGetError();
-        if (err != EGL10.EGL_SUCCESS) {
-            // give-up on using GL
-            destroyGL();
-            mGlWanted = false;
-        }
-    }
-
-    private void initializeGLInner() {
-        final EGL10 egl = (EGL10) EGLContext.getEGL();
-        mEgl = egl;
-
-        /*
-         * Get to the default display.
-         */
-        final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-        mEglDisplay = eglDisplay;
-
-        /*
-         * We can now initialize EGL for that display
-         */
-        int[] version = new int[2];
-        egl.eglInitialize(eglDisplay, version);
-
-        /*
-         * Specify a configuration for our opengl session
-         * and grab the first configuration that matches is
-         */
-        final int[] configSpec = {
-                EGL10.EGL_RED_SIZE,      5,
-                EGL10.EGL_GREEN_SIZE,    6,
-                EGL10.EGL_BLUE_SIZE,     5,
-                EGL10.EGL_DEPTH_SIZE,    0,
-                EGL10.EGL_NONE
-        };
-        final EGLConfig[] configs = new EGLConfig[1];
-        final int[] num_config = new int[1];
-        egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, num_config);
-        final EGLConfig config = configs[0];
-
-        /*
-         * Create an OpenGL ES context. This must be done only once, an
-         * OpenGL context is a somewhat heavy object.
-         */
-        final EGLContext context = egl.eglCreateContext(eglDisplay, config,
-                EGL10.EGL_NO_CONTEXT, null);
-        mEglContext = context;
-
-        /*
-         * Create an EGL surface we can render into.
-         */
-        final EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
-        mEglSurface = surface;
-
-        /*
-         * Before we can issue GL commands, we need to make sure
-         * the context is current and bound to a surface.
-         */
-        egl.eglMakeCurrent(eglDisplay, surface, surface, context);
-
-        /*
-         * Get to the appropriate GL interface.
-         * This is simply done by casting the GL context to either
-         * GL10 or GL11.
-         */
-        final GL11 gl = (GL11) context.getGL();
-        mGL = gl;
-        mGlCanvas = new Canvas(gl);
-        mUseGL = true;
-    }
-
-    private void destroyGL() {
-        // inform skia that the context is gone
-        nativeAbandonGlCaches();
-
-        mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
-                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
-        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-        mEgl.eglTerminate(mEglDisplay);
-        mEglContext = null;
-        mEglSurface = null;
-        mEglDisplay = null;
-        mEgl = null;
-        mGlCanvas = null;
-        mGL = null;
-        mUseGL = false;
-    }
-
-    private void checkEglErrors() {
-        if (mUseGL) {
-            int err = mEgl.eglGetError();
-            if (err != EGL10.EGL_SUCCESS) {
-                // something bad has happened revert to
-                // normal rendering.
-                destroyGL();
-                if (err != EGL11.EGL_CONTEXT_LOST) {
-                    // we'll try again if it was context lost
-                    mGlWanted = false;
-                }
-            }
-        }
-    }
-
     // fd [0] is the receiver, [1] is the sender
     private native int[] makeInputChannel();
 
@@ -490,10 +382,10 @@
 
                 // Set up the input event channel
                 if (false) {
-                int[] fds = makeInputChannel();
-                if (DEBUG_INPUT) {
-                    Log.v(TAG, "makeInputChannel() returned " + fds);
-                }
+                    int[] fds = makeInputChannel();
+                    if (DEBUG_INPUT) {
+                        Log.v(TAG, "makeInputChannel() returned " + java.util.Arrays.toString(fds));
+                    }
                 }
 
                 // Schedule the first layout -before- adding to the window
@@ -772,8 +664,8 @@
             attachInfo.mWindowVisibility = viewVisibility;
             host.dispatchWindowVisibilityChanged(viewVisibility);
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
-                if (mUseGL) {
-                    destroyGL();
+                if (mHwRenderer != null) {
+                    mHwRenderer.destroyGL();
                 }
             }
             if (viewVisibility == View.GONE) {
@@ -889,10 +781,12 @@
 
         final boolean computesInternalInsets =
                 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
+
         boolean insetsPending = false;
         int relayoutResult = 0;
-        if (mFirst || windowShouldResize || insetsChanged
-                || viewVisibilityChanged || params != null) {
+
+        if (mFirst || windowShouldResize || insetsChanged ||
+                viewVisibilityChanged || params != null) {
 
             if (viewVisibility == View.VISIBLE) {
                 // If this window is giving internal insets to the window
@@ -904,15 +798,7 @@
                 // window, waiting until we can finish laying out this window
                 // and get back to the window manager with the ultimately
                 // computed insets.
-                insetsPending = computesInternalInsets
-                        && (mFirst || viewVisibilityChanged);
-
-                if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
-                    if (params == null) {
-                        params = mWindowAttributes;
-                    }
-                    mGlWanted = true;
-                }
+                insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
             }
 
             if (mSurfaceHolder != null) {
@@ -921,11 +807,12 @@
                 lp.format = mSurfaceHolder.getRequestedFormat();
                 lp.type = mSurfaceHolder.getRequestedType();
             }
-            
-            boolean initialized = false;
+
+            boolean hwIntialized = false;
             boolean contentInsetsChanged = false;
             boolean visibleInsetsChanged;
             boolean hadSurface = mSurface.isValid();
+
             try {
                 int fl = 0;
                 if (params != null) {
@@ -985,9 +872,8 @@
                         fullRedrawNeeded = true;
                         mPreviousTransparentRegion.setEmpty();
 
-                        if (mGlWanted && !mUseGL) {
-                            initializeGL();
-                            initialized = mGlCanvas != null;
+                        if (mHwRenderer != null) {
+                            hwIntialized = mHwRenderer.initialize();
                         }
                     }
                 } else if (!mSurface.isValid()) {
@@ -1065,9 +951,8 @@
                 }
             }
             
-            if (initialized) {
-                mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
-                        (int) (mHeight * appScale + 0.5f));
+            if (hwIntialized) {
+                mHwRenderer.setup(appScale);
             }
 
             boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1328,7 +1213,8 @@
         if (!sFirstDrawComplete) {
             synchronized (sFirstDrawHandlers) {
                 sFirstDrawComplete = true;
-                for (int i=0; i<sFirstDrawHandlers.size(); i++) {
+                final int count = sFirstDrawHandlers.size();
+                for (int i = 0; i< count; i++) {
                     post(sFirstDrawHandlers.get(i));
                 }
             }
@@ -1362,53 +1248,16 @@
             return;
         }
         
-        if (mUseGL) {
+        if (mHwRenderer != null && mHwRenderer.mEnabled) {
             if (!dirty.isEmpty()) {
-                Canvas canvas = mGlCanvas;
-                if (mGL != null && canvas != null) {
-                    mGL.glDisable(GL_SCISSOR_TEST);
-                    mGL.glClearColor(0, 0, 0, 0);
-                    mGL.glClear(GL_COLOR_BUFFER_BIT);
-                    mGL.glEnable(GL_SCISSOR_TEST);
-
-                    mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
-                    mAttachInfo.mIgnoreDirtyState = true;
-                    mView.mPrivateFlags |= View.DRAWN;
-
-                    int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                    try {
-                        canvas.translate(0, -yoff);
-                        if (mTranslator != null) {
-                            mTranslator.translateCanvas(canvas);
-                        }
-                        canvas.setScreenDensity(scalingRequired
-                                ? DisplayMetrics.DENSITY_DEVICE : 0);
-                        mView.draw(canvas);
-                        if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
-                            mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
-                        }
-                    } finally {
-                        canvas.restoreToCount(saveCount);
-                    }
-
-                    mAttachInfo.mIgnoreDirtyState = false;
-
-                    mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
-                    checkEglErrors();
-
-                    if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) {
-                        int now = (int)SystemClock.elapsedRealtime();
-                        if (sDrawTime != 0) {
-                            nativeShowFPS(canvas, now - sDrawTime);
-                        }
-                        sDrawTime = now;
-                    }
-                }
+                mHwRenderer.draw(yoff, scalingRequired);
             }
+
             if (scrolling) {
                 mFullRedrawNeeded = true;
                 scheduleTraversals();
             }
+
             return;
         }
 
@@ -1720,8 +1569,6 @@
     }
 
     void dispatchDetachedFromWindow() {
-        if (Config.LOGV) Log.v("ViewRoot", "Detaching in " + this + " of " + mSurface);
-
         if (mView != null) {
             mView.dispatchDetachedFromWindow();
         }
@@ -1730,8 +1577,8 @@
         mAttachInfo.mRootView = null;
         mAttachInfo.mSurface = null;
 
-        if (mUseGL) {
-            destroyGL();
+        if (mHwRenderer != null) {
+            mHwRenderer.destroyGL();
         }
         mSurface.release();
 
@@ -1850,8 +1697,10 @@
                     event = sWindowSession.getPendingPointerMove(mWindow);
 
                     if (MEASURE_LATENCY && event != null) {
-                        lt.sample("9 Client got events      ", System.nanoTime() - event.getEventTimeNano());
-                        lt.sample("8 Client getting events  ", timeBeforeGettingEvents - event.getEventTimeNano());
+                        lt.sample("9 Client got events      ",
+                                System.nanoTime() - event.getEventTimeNano());
+                        lt.sample("8 Client getting events  ",
+                                timeBeforeGettingEvents - event.getEventTimeNano());
                     }
                 } catch (RemoteException e) {
                 }
@@ -1876,11 +1725,13 @@
                         event.offsetLocation(0, mCurScrollY);
                     }
                     if (MEASURE_LATENCY) {
-                        lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+                        lt.sample("A Dispatching TouchEvents",
+                                System.nanoTime() - event.getEventTimeNano());
                     }
                     handled = mView.dispatchTouchEvent(event);
                     if (MEASURE_LATENCY) {
-                        lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+                        lt.sample("B Dispatched TouchEvents ",
+                                System.nanoTime() - event.getEventTimeNano());
                     }
                     if (!handled && isDown) {
                         int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
@@ -1990,18 +1841,8 @@
                     boolean inTouchMode = msg.arg2 != 0;
                     ensureTouchModeLocally(inTouchMode);
 
-                    if (mGlWanted) {
-                        checkEglErrors();
-                        // we lost the gl context, so recreate it.
-                        if (mGlWanted && !mUseGL) {
-                            initializeGL();
-                            if (mGlCanvas != null) {
-                                float appScale = mAttachInfo.mApplicationScale;
-                                mGlCanvas.setViewport(
-                                        (int) (mWidth * appScale + 0.5f),
-                                        (int) (mHeight * appScale + 0.5f));
-                            }
-                        }
+                    if (mHwRenderer != null) {
+                        mHwRenderer.initializeAndSetup();
                     }
                 }
 
@@ -2051,8 +1892,7 @@
             if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
                 // The IME is trying to say this event is from the
                 // system!  Bad bad bad!
-                event = KeyEvent.changeFlags(event,
-                        event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
+                event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
             }
             deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
         } break;
@@ -2497,8 +2337,7 @@
     private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
         // If mView is null, we just consume the key event because it doesn't
         // make sense to do anything else with it.
-        boolean handled = mView != null
-                ? mView.dispatchKeyEventPreIme(event) : true;
+        boolean handled = mView == null || mView.dispatchKeyEventPreIme(event);
         if (handled) {
             if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
@@ -2535,7 +2374,6 @@
             final boolean sendDone = seq >= 0;
             if (!handled) {
                 deliverKeyEventToViewHierarchy(event, sendDone);
-                return;
             } else if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
                         "ViewRoot", "Telling window manager key is finished");
@@ -2742,7 +2580,7 @@
 
     void doDie() {
         checkThread();
-        if (Config.LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
+        if (LOCAL_LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
         synchronized (this) {
             if (mAdded && !mFirst) {
                 int viewVisibility = mView.getVisibility();
@@ -2803,13 +2641,12 @@
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             //noinspection ConstantConditions
             if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
-                if (Config.LOGD) Log.d("keydisp",
-                        "===================================================");
-                if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
+                if (DBG) Log.d("keydisp", "===================================================");
+                if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
+
                 debug();
 
-                if (Config.LOGD) Log.d("keydisp",
-                        "===================================================");
+                if (DBG) Log.d("keydisp", "===================================================");
             }
         }
 
@@ -3476,6 +3313,180 @@
         }
     }
 
+    class HardwareRenderer {
+        private EGL10 mEgl;
+        private EGLDisplay mEglDisplay;
+        private EGLContext mEglContext;
+        private EGLSurface mEglSurface;
+        private GL11 mGL;
+
+        private Canvas mGlCanvas;
+
+        boolean mEnabled;
+        boolean mRequested = true;
+
+        private void initializeGL() {
+            initializeGLInner();
+            int err = mEgl.eglGetError();
+            if (err != EGL10.EGL_SUCCESS) {
+                destroyGL();
+                mRequested = false;
+            }
+        }
+
+        private void initializeGLInner() {
+            final EGL10 egl = (EGL10) EGLContext.getEGL();
+            mEgl = egl;
+    
+            final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+            mEglDisplay = eglDisplay;
+    
+            int[] version = new int[2];
+            egl.eglInitialize(eglDisplay, version);
+    
+            final int[] configSpec = {
+                    EGL10.EGL_RED_SIZE,      8,
+                    EGL10.EGL_GREEN_SIZE,    8,
+                    EGL10.EGL_BLUE_SIZE,     8,
+                    EGL10.EGL_DEPTH_SIZE,    0,
+                    EGL10.EGL_NONE
+            };
+            final EGLConfig[] configs = new EGLConfig[1];
+            final int[] numConfig = new int[1];
+            egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, numConfig);
+            final EGLConfig config = configs[0];
+
+            /*
+             * Create an OpenGL ES context. This must be done only once, an
+             * OpenGL context is a somewhat heavy object.
+             */
+            final EGLContext context = egl.eglCreateContext(eglDisplay, config,
+                    EGL10.EGL_NO_CONTEXT, null);
+            mEglContext = context;
+    
+            /*
+             * Create an EGL surface we can render into.
+             */
+            EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
+            mEglSurface = surface;
+    
+            /*
+             * Before we can issue GL commands, we need to make sure
+             * the context is current and bound to a surface.
+             */
+            egl.eglMakeCurrent(eglDisplay, surface, surface, context);
+    
+            /*
+             * Get to the appropriate GL interface.
+             * This is simply done by casting the GL context to either
+             * GL10 or GL11.
+             */
+            final GL11 gl = (GL11) context.getGL();
+            mGL = gl;
+            mGlCanvas = new Canvas(gl);
+            mEnabled = true;
+        }
+
+        void destroyGL() {
+            if (!mEnabled) return;
+            
+            // inform skia that the context is gone
+            nativeAbandonGlCaches();
+    
+            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+            mEgl.eglTerminate(mEglDisplay);
+
+            mEglContext = null;
+            mEglSurface = null;
+            mEglDisplay = null;
+            mEgl = null;
+            mGlCanvas = null;
+            mGL = null;
+
+            mEnabled = false;
+        }
+    
+        private void checkErrors() {
+            if (mEnabled) {
+                int err = mEgl.eglGetError();
+                if (err != EGL10.EGL_SUCCESS) {
+                    // something bad has happened revert to
+                    // normal rendering.
+                    destroyGL();
+                    if (err != EGL11.EGL_CONTEXT_LOST) {
+                        // we'll try again if it was context lost
+                        mRequested = false;
+                    }
+                }
+            }
+        }
+
+        boolean initialize() {
+            if (mRequested && !mEnabled) {
+                initializeGL();
+                return mGlCanvas != null;
+            }
+            return false;
+        }
+
+        void setup(float appScale) {
+            mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
+                    (int) (mHeight * appScale + 0.5f));
+        }
+
+        void draw(int yoff, boolean scalingRequired) {
+            Canvas canvas = mGlCanvas;
+            if (mGL != null && canvas != null) {
+                mGL.glDisable(GL_SCISSOR_TEST);
+                mGL.glClearColor(0, 0, 0, 0);
+                mGL.glClear(GL_COLOR_BUFFER_BIT);
+                mGL.glEnable(GL_SCISSOR_TEST);
+    
+                mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
+                mAttachInfo.mIgnoreDirtyState = true;
+                mView.mPrivateFlags |= View.DRAWN;
+    
+                int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                try {
+                    canvas.translate(0, -yoff);
+                    if (mTranslator != null) {
+                        mTranslator.translateCanvas(canvas);
+                    }
+                    canvas.setScreenDensity(scalingRequired ?
+                            DisplayMetrics.DENSITY_DEVICE : 0);
+    
+                    mView.draw(canvas);
+    
+                } finally {
+                    canvas.restoreToCount(saveCount);
+                }
+    
+                mAttachInfo.mIgnoreDirtyState = false;
+    
+                mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
+                checkErrors();
+            }
+        }
+
+        void initializeAndSetup() {
+            if (mRequested) {
+                checkErrors();
+                // we lost the gl context, so recreate it.
+                if (mRequested && !mEnabled) {
+                    initializeGL();
+                    if (mGlCanvas != null) {
+                        float appScale = mAttachInfo.mApplicationScale;
+                        mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
+                                (int) (mHeight * appScale + 0.5f));
+                    }
+                }
+            }
+        }
+    }
+    
     private static native void nativeShowFPS(Canvas canvas, int durationMillis);
 
     // inform skia to just abandon its texture cache IDs
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index cfeb8fb..ecad261 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -51,7 +51,7 @@
     /* package */
     static final int REFRESH_PLUGINS = 100;
 
-    private HashMap<String, String> mContentUriToFileNameMap;
+    private HashMap<String, String> mContentUriToFilePathMap;
 
     /**
      * Construct a new JWebCoreJavaBridge to interface with
@@ -273,9 +273,9 @@
     }
 
     // Called on the WebCore thread through JNI.
-    private String resolveFileNameForContentUri(String uri) {
-        if (mContentUriToFileNameMap != null) {
-            String fileName = mContentUriToFileNameMap.get(uri);
+    private String resolveFilePathForContentUri(String uri) {
+        if (mContentUriToFilePathMap != null) {
+            String fileName = mContentUriToFilePathMap.get(uri);
             if (fileName != null) {
                 return fileName;
             }
@@ -287,11 +287,11 @@
         return jUri.getLastPathSegment();
     }
 
-    public void storeFileNameForContentUri(String fileName, String contentUri) {
-        if (mContentUriToFileNameMap == null) {
-            mContentUriToFileNameMap = new HashMap<String, String>();
+    public void storeFilePathForContentUri(String path, String contentUri) {
+        if (mContentUriToFilePathMap == null) {
+            mContentUriToFilePathMap = new HashMap<String, String>();
         }
-        mContentUriToFileNameMap.put(contentUri, fileName);
+        mContentUriToFilePathMap.put(contentUri, path);
     }
 
     private native void nativeConstructor();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1cc5ab7..6c0e6b6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -30,7 +30,6 @@
 import android.graphics.CornerPathEffect;
 import android.graphics.Interpolator;
 import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.Picture;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -1055,7 +1054,7 @@
     /*
      * Return the amount of the titlebarview (if any) that is visible
      */
-    private int getVisibleTitleHeight() {
+    int getVisibleTitleHeight() {
         return Math.max(getTitleHeight() - mScrollY, 0);
     }
 
@@ -1763,7 +1762,7 @@
      * @param scaleInPercent The initial scale in percent.
      */
     public void setInitialScale(int scaleInPercent) {
-        mInitialScaleInPercent = scaleInPercent;
+        mZoomManager.setInitialScaleInPercent(scaleInPercent);
     }
 
     /**
@@ -2248,7 +2247,7 @@
         if (mDrawHistory) {
             return mHistoryWidth;
         } else if (mHorizontalScrollBarMode == SCROLLBAR_ALWAYSOFF
-                && mZoomManager.isZoomedOut()) {
+                && !mZoomManager.canZoomOut()) {
             // only honor the scrollbar mode when it is at minimum zoom level
             return computeHorizontalScrollExtent();
         } else {
@@ -2262,7 +2261,7 @@
         if (mDrawHistory) {
             return mHistoryHeight;
         } else if (mVerticalScrollBarMode == SCROLLBAR_ALWAYSOFF
-                && mZoomManager.isZoomedOut()) {
+                && !mZoomManager.canZoomOut()) {
             // only honor the scrollbar mode when it is at minimum zoom level
             return computeVerticalScrollExtent();
         } else {
@@ -3387,6 +3386,10 @@
         return mDrawHistory;
     }
 
+    int getHistoryPictureWidth() {
+        return (mHistoryPicture != null) ? mHistoryPicture.getWidth() : 0;
+    }
+
     // Should only be called in UI thread
     void switchOutDrawHistory() {
         if (null == mWebViewCore) return; // CallbackProxy may trigger this
@@ -3462,11 +3465,11 @@
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
 
         // bring it back to the default scale so that user can enter text
-        boolean zoom = mZoomManager.mActualScale < mZoomManager.mDefaultScale;
+        boolean zoom = mZoomManager.mActualScale < mZoomManager.getDefaultScale();
         if (zoom) {
             mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
             mZoomManager.mInZoomOverview = false;
-            mZoomManager.setZoomScale(mZoomManager.mDefaultScale, false);
+            mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false);
         }
         if (isTextView) {
             rebuildWebTextView();
@@ -4143,73 +4146,19 @@
         return changed;
     }
 
-    private static class PostScale implements Runnable {
-        final WebView mWebView;
-        final boolean mUpdateTextWrap;
-
-        public PostScale(WebView webView, boolean updateTextWrap) {
-            mWebView = webView;
-            mUpdateTextWrap = updateTextWrap;
-        }
-
-        public void run() {
-            if (mWebView.mWebViewCore != null) {
-                // we always force, in case our height changed, in which case we
-                // still want to send the notification over to webkit.
-                mWebView.mZoomManager.refreshZoomScale(mUpdateTextWrap);
-                // update the zoom buttons as the scale can be changed
-                mWebView.mZoomManager.updateZoomPicker();
-            }
-        }
-    }
-
     @Override
     protected void onSizeChanged(int w, int h, int ow, int oh) {
         super.onSizeChanged(w, h, ow, oh);
-        // reset zoom and anchor to the top left corner of the screen
-        // unless we are already zooming
-        if (!mZoomManager.isZoomAnimating()) {
-            int visibleTitleHeight = getVisibleTitleHeight();
-            mZoomManager.setZoomCenter(0, visibleTitleHeight);
-            mAnchorX = viewToContentX(mScrollX);
-            mAnchorY = viewToContentY(visibleTitleHeight + mScrollY);
-        }
 
         // adjust the max viewport width depending on the view dimensions. This
         // is to ensure the scaling is not going insane. So do not shrink it if
         // the view size is temporarily smaller, e.g. when soft keyboard is up.
-        int newMaxViewportWidth = (int) (Math.max(w, h) / mZoomManager.DEFAULT_MIN_ZOOM_SCALE);
+        int newMaxViewportWidth = (int) (Math.max(w, h) / ZoomManager.DEFAULT_MIN_ZOOM_SCALE);
         if (newMaxViewportWidth > sMaxViewportWidth) {
             sMaxViewportWidth = newMaxViewportWidth;
         }
 
-        // update mMinZoomScale if the minimum zoom scale is not fixed
-        if (!mZoomManager.mMinZoomScaleFixed) {
-            // when change from narrow screen to wide screen, the new viewWidth
-            // can be wider than the old content width. We limit the minimum
-            // scale to 1.0f. The proper minimum scale will be calculated when
-            // the new picture shows up.
-            mZoomManager.mMinZoomScale = Math.min(1.0f, (float) getViewWidth()
-                    / (mDrawHistory ? mHistoryPicture.getWidth()
-                            : mZoomManager.mZoomOverviewWidth));
-            if (mInitialScaleInPercent > 0) {
-                // limit the minZoomScale to the initialScale if it is set
-                float initialScale = mInitialScaleInPercent / 100.0f;
-                if (mZoomManager.mMinZoomScale > initialScale) {
-                    mZoomManager.mMinZoomScale = initialScale;
-                }
-            }
-        }
-
-        mZoomManager.dismissZoomPicker();
-
-        // onSizeChanged() is called during WebView layout. And any
-        // requestLayout() is blocked during layout. As setNewZoomScale() will
-        // call its child View to reposition itself through ViewManager's
-        // scaleAll(), we need to post a Runnable to ensure requestLayout().
-        // <b/>
-        // only update the text wrap scale if width changed.
-        post(new PostScale(this, w != ow));
+        mZoomManager.onSizeChanged(w, h, ow, oh);
     }
 
     @Override
@@ -4493,7 +4442,7 @@
                 mAnchorY = viewToContentY((int) mZoomManager.mZoomCenterY + mScrollY);
                 // don't reflow when zoom in; when zoom out, do reflow if the
                 // new scale is almost minimum scale;
-                boolean reflowNow = mZoomManager.isZoomedOut()
+                boolean reflowNow = !mZoomManager.canZoomOut()
                         || (mZoomManager.mActualScale <= 0.8 * mZoomManager.mTextWrapScale);
                 // force zoom after mPreviewZoomOnly is set to false so that the
                 // new view size will be passed to the WebKit
@@ -5001,7 +4950,10 @@
                                 break;
                             }
                         } else {
-                            if (mTouchMode == TOUCH_INIT_MODE) {
+                            // only trigger double tap if the WebView is
+                            // scalable
+                            if (mTouchMode == TOUCH_INIT_MODE
+                                    && (canZoomIn() || canZoomOut())) {
                                 mPrivateHandler.sendEmptyMessageDelayed(
                                         RELEASE_SINGLE_TAP, ViewConfiguration
                                                 .getDoubleTapTimeout());
@@ -5553,7 +5505,21 @@
     }
 
     float getDefaultZoomScale() {
-        return mZoomManager.mDefaultScale;
+        return mZoomManager.getDefaultScale();
+    }
+
+    /**
+     * @return TRUE if the WebView can be zoomed in.
+     */
+    public boolean canZoomIn() {
+        return mZoomManager.canZoomIn();
+    }
+
+    /**
+     * @return TRUE if the WebView can be zoomed out.
+     */
+    public boolean canZoomOut() {
+        return mZoomManager.canZoomOut();
     }
 
     /**
@@ -5820,7 +5786,7 @@
             float newScale = (float) getViewWidth() / mZoomManager.mZoomOverviewWidth;
             if (mZoomManager.willScaleTriggerZoom(newScale)) {
                 mZoomManager.zoomToOverview();
-            } else if (mZoomManager.willScaleTriggerZoom(mZoomManager.mDefaultScale)) {
+            } else if (mZoomManager.willScaleTriggerZoom(mZoomManager.getDefaultScale())) {
                 zoomToDefault = true;
             }
         } else {
@@ -5835,8 +5801,8 @@
                 // Re-calculate the zoom center so that the new scroll x will be
                 // on the left edge.
                 if (viewLeft > 0) {
-                    mZoomManager.mZoomCenterX = viewLeft * mZoomManager.mDefaultScale
-                            / (mZoomManager.mDefaultScale - mZoomManager.mActualScale);
+                    mZoomManager.mZoomCenterX = viewLeft * mZoomManager.getDefaultScale()
+                            / (mZoomManager.getDefaultScale() - mZoomManager.mActualScale);
                 } else {
                     scrollBy(viewLeft, 0);
                     mZoomManager.mZoomCenterX = 0;
@@ -6160,7 +6126,7 @@
                     WebViewCore.RestoreState restoreState
                             = (WebViewCore.RestoreState) msg.obj;
                     // mScrollX contains the new minPrefWidth
-                    updateZoomRange(restoreState, getViewWidth(),
+                    mZoomManager.updateZoomRange(restoreState, getViewWidth(),
                             restoreState.mScrollX, false);
                     break;
                 }
@@ -6171,54 +6137,24 @@
                         mDelayedDeleteRootLayer = false;
                         nativeSetRootLayer(0);
                     }
-                    WebSettings settings = mWebViewCore.getSettings();
                     // called for new content
-                    final int viewWidth = getViewWidth();
-                    final WebViewCore.DrawData draw =
-                            (WebViewCore.DrawData) msg.obj;
+                    final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
+
                     final Point viewSize = draw.mViewPoint;
-                    boolean useWideViewport = settings.getUseWideViewPort();
                     WebViewCore.RestoreState restoreState = draw.mRestoreState;
                     boolean hasRestoreState = restoreState != null;
                     if (hasRestoreState) {
-                        updateZoomRange(restoreState, viewSize.x,
-                                draw.mMinPrefWidth, true);
+                        mZoomManager.restoreZoomState(draw);
                         if (!mDrawHistory) {
-                            mZoomManager.mInZoomOverview = false;
-
-                            if (mInitialScaleInPercent > 0) {
-                                final float initialScale = mInitialScaleInPercent / 100.0f;
-                                final boolean reflowText =
-                                    mInitialScaleInPercent != mZoomManager.mTextWrapScale * 100;
-                                mZoomManager.setZoomScale(initialScale, reflowText);
-                            } else if (restoreState.mViewScale > 0) {
-                                mZoomManager.mTextWrapScale = restoreState.mTextWrapScale;
-                                mZoomManager.setZoomScale(restoreState.mViewScale, false);
-                            } else {
-                                mZoomManager.mInZoomOverview = useWideViewport
-                                    && settings.getLoadWithOverviewMode();
-                                float scale;
-                                if (mZoomManager.mInZoomOverview) {
-                                    scale = (float) viewWidth
-                                        / DEFAULT_VIEWPORT_WIDTH;
-                                } else {
-                                    scale = restoreState.mTextWrapScale;
-                                }
-                                mZoomManager.setZoomScale(scale,
-                                        ZoomManager.exceedsMinScaleIncrement(
-                                        mZoomManager.mTextWrapScale, scale));
-                            }
-                            setContentScrollTo(restoreState.mScrollX,
-                                restoreState.mScrollY);
+                            setContentScrollTo(restoreState.mScrollX, restoreState.mScrollY);
                             // As we are on a new page, remove the WebTextView. This
                             // is necessary for page loads driven by webkit, and in
                             // particular when the user was on a password field, so
                             // the WebTextView was visible.
                             clearTextEntry(false);
-                            // update the zoom buttons as the scale can be changed
-                            mZoomManager.updateZoomPicker();
                         }
                     }
+
                     // We update the layout (i.e. request a layout from the
                     // view system) if the last view size that we sent to
                     // WebCore matches the view size of the picture we just
@@ -6233,33 +6169,14 @@
                                 b.left+","+b.top+","+b.right+","+b.bottom+"}");
                     }
                     invalidateContentRect(draw.mInvalRegion.getBounds());
+
                     if (mPictureListener != null) {
                         mPictureListener.onNewPicture(WebView.this, capturePicture());
                     }
-                    if (useWideViewport) {
-                        // limit mZoomOverviewWidth upper bound to
-                        // sMaxViewportWidth so that if the page doesn't behave
-                        // well, the WebView won't go insane. limit the lower
-                        // bound to match the default scale for mobile sites.
-                        mZoomManager.mZoomOverviewWidth = Math.min(sMaxViewportWidth, Math
-                                .max((int) (viewWidth / mZoomManager.mDefaultScale),
-                                        Math.max(draw.mMinPrefWidth,
-                                                draw.mViewPoint.x)));
-                    }
-                    if (!mZoomManager.mMinZoomScaleFixed) {
-                        mZoomManager.mMinZoomScale = (float) viewWidth / 
-                            mZoomManager.mZoomOverviewWidth;
-                    }
-                    if (!mDrawHistory && mZoomManager.mInZoomOverview) {
-                        // fit the content width to the current view. Ignore
-                        // the rounding error case.
-                        if (Math.abs((viewWidth * mZoomManager.mInvActualScale)
-                                - mZoomManager.mZoomOverviewWidth) > 1) {
-                            mZoomManager.setZoomScale(
-                                    (float) viewWidth / mZoomManager.mZoomOverviewWidth,
-                                    !mZoomManager.willScaleTriggerZoom(mZoomManager.mTextWrapScale));
-                        }
-                    }
+
+                    // update the zoom information based on the new picture
+                    mZoomManager.onNewPicture(draw);
+
                     if (draw.mFocusSizeChanged && inEditingMode()) {
                         mFocusSizeChanged = true;
                     }
@@ -6927,37 +6844,6 @@
                 new InvokeListBox(array, enabledArray, selectedArray));
     }
 
-    private void updateZoomRange(WebViewCore.RestoreState restoreState,
-            int viewWidth, int minPrefWidth, boolean updateZoomOverview) {
-        if (restoreState.mMinScale == 0) {
-            if (restoreState.mMobileSite) {
-                if (minPrefWidth > Math.max(0, viewWidth)) {
-                    mZoomManager.mMinZoomScale = (float) viewWidth / minPrefWidth;
-                    mZoomManager.mMinZoomScaleFixed = false;
-                    if (updateZoomOverview) {
-                        WebSettings settings = getSettings();
-                        mZoomManager.mInZoomOverview = settings.getUseWideViewPort() &&
-                                settings.getLoadWithOverviewMode();
-                    }
-                } else {
-                    mZoomManager.mMinZoomScale = restoreState.mDefaultScale;
-                    mZoomManager.mMinZoomScaleFixed = true;
-                }
-            } else {
-                mZoomManager.mMinZoomScale = mZoomManager.DEFAULT_MIN_ZOOM_SCALE;
-                mZoomManager.mMinZoomScaleFixed = false;
-            }
-        } else {
-            mZoomManager.mMinZoomScale = restoreState.mMinScale;
-            mZoomManager.mMinZoomScaleFixed = true;
-        }
-        if (restoreState.mMaxScale == 0) {
-            mZoomManager.mMaxZoomScale = mZoomManager.DEFAULT_MAX_ZOOM_SCALE;
-        } else {
-            mZoomManager.mMaxZoomScale = restoreState.mMaxScale;
-        }
-    }
-
     /*
      * Request a dropdown menu for a listbox with single selection or a single
      * <select> element.
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 850cc25..5139ae8 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -32,7 +32,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
-import android.provider.OpenableColumns;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Images.Media;
 import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.KeyEvent;
@@ -283,24 +284,26 @@
     private String openFileChooser(String acceptType) {
         Uri uri = mCallbackProxy.openFileChooser(acceptType);
         if (uri != null) {
-            String fileName = "";
+            String filePath = "";
+            // Note - querying for MediaStore.Images.Media.DATA
+            // seems to work for all content URIs, not just images
             Cursor cursor = mContext.getContentResolver().query(
                     uri,
-                    new String[] { OpenableColumns.DISPLAY_NAME },
+                    new String[] { MediaStore.Images.Media.DATA },
                     null, null, null);
             if (cursor != null) {
                 try {
                     if (cursor.moveToNext()) {
-                        fileName = cursor.getString(0);
+                        filePath = cursor.getString(0);
                     }
                 } finally {
                     cursor.close();
                 }
             } else {
-                fileName = uri.getLastPathSegment();
+                filePath = uri.getLastPathSegment();
             }
             String uriString = uri.toString();
-            BrowserFrame.sJavaBridge.storeFileNameForContentUri(fileName, uriString);
+            BrowserFrame.sJavaBridge.storeFilePathForContentUri(filePath, uriString);
             return uriString;
         }
         return "";
diff --git a/core/java/android/webkit/ZoomControlEmbedded.java b/core/java/android/webkit/ZoomControlEmbedded.java
index cd02c00..2036635 100644
--- a/core/java/android/webkit/ZoomControlEmbedded.java
+++ b/core/java/android/webkit/ZoomControlEmbedded.java
@@ -67,9 +67,8 @@
             return;
         }
 
-        boolean canZoomIn = mWebView.getScale() < mZoomManager.mMaxZoomScale;
-        boolean canZoomOut = mWebView.getScale() > mZoomManager.mMinZoomScale &&
-                                                  !mZoomManager.mInZoomOverview;
+        boolean canZoomIn = mZoomManager.canZoomIn();
+        boolean canZoomOut = mZoomManager.canZoomOut() && !mZoomManager.mInZoomOverview;
         if (!canZoomIn && !canZoomOut) {
             // Hide the zoom in and out buttons if the page cannot zoom
             mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 4028004..1540865 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -16,7 +16,7 @@
 
 package android.webkit;
 
-import android.graphics.Canvas;
+import android.graphics.Point;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.View;
@@ -68,7 +68,8 @@
 
     // the default zoom scale. This value will is initially set based on the
     // display density, but can be changed at any time via the WebSettings.
-    float mDefaultScale;
+    private float mDefaultScale;
+    private float mInvDefaultScale;
 
     private static float MINIMUM_SCALE_INCREMENT = 0.01f;
 
@@ -80,6 +81,16 @@
     float mInvActualScale;
     
     /*
+     * The initial scale for the WebView. 0 means default. If initial scale is
+     * greater than 0 the WebView starts with this value as its initial scale. The
+     * value is converted from an integer percentage so it is guarenteed to have
+     * no more than 2 significant digits after the decimal.  This restriction
+     * allows us to convert the scale back to the original percentage by simply
+     * multiplying the value by 100.
+     */
+    private float mInitialScale;
+
+    /*
      * The following member variables are only to be used for animating zoom. If
      * mZoomScale is non-zero then we are in the middle of a zoom animation. The
      * other variables are used as a cache (e.g. inverse) or as a way to store
@@ -109,7 +120,7 @@
 
     public void updateDefaultZoomDensity(float density) {
         if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
-            float scaleFactor = density / mDefaultScale;
+            float scaleFactor = density * mInvDefaultScale;
             // set the new default density
             setDefaultZoomScale(density);
             // adjust the limits
@@ -121,15 +132,24 @@
 
     private void setDefaultZoomScale(float defaultScale) {
         mDefaultScale = defaultScale;
+        mInvDefaultScale = 1 / defaultScale;
         DEFAULT_MAX_ZOOM_SCALE = 4.0f * defaultScale;
         DEFAULT_MIN_ZOOM_SCALE = 0.25f * defaultScale;
     }
 
+    public float getDefaultScale() {
+        return mDefaultScale;
+    }
+
     public void setZoomCenter(float x, float y) {
         mZoomCenterX = x;
         mZoomCenterY = y;
     }
 
+    public void setInitialScaleInPercent(int scaleInPercent) {
+        mInitialScale = scaleInPercent * 0.01f;
+    }
+
     public static final boolean exceedsMinScaleIncrement(float scaleA, float scaleB) {
         return Math.abs(scaleA - scaleB) >= MINIMUM_SCALE_INCREMENT;
     }
@@ -138,8 +158,12 @@
         return exceedsMinScaleIncrement(scale, mActualScale);
     }
 
-    public boolean isZoomedOut() {
-        return mActualScale - mMinZoomScale <= MINIMUM_SCALE_INCREMENT;
+    public boolean canZoomIn() {
+        return mMaxZoomScale - mActualScale > MINIMUM_SCALE_INCREMENT;
+    }
+
+    public boolean canZoomOut() {
+        return mActualScale - mMinZoomScale > MINIMUM_SCALE_INCREMENT;
     }
 
     public boolean zoomIn() {
@@ -333,6 +357,169 @@
         }
     }
 
+    public void onSizeChanged(int w, int h, int ow, int oh) {
+        // reset zoom and anchor to the top left corner of the screen
+        // unless we are already zooming
+        if (!isZoomAnimating()) {
+            int visibleTitleHeight = mWebView.getVisibleTitleHeight();
+            mZoomCenterX = 0;
+            mZoomCenterY = visibleTitleHeight;
+            int anchorX = mWebView.viewToContentX(mWebView.getScrollX());
+            int anchorY = mWebView.viewToContentY(visibleTitleHeight + mWebView.getScrollY());
+            mWebView.setViewSizeAnchor(anchorX, anchorY);
+
+        }
+
+        // update mMinZoomScale if the minimum zoom scale is not fixed
+        if (!mMinZoomScaleFixed) {
+            // when change from narrow screen to wide screen, the new viewWidth
+            // can be wider than the old content width. We limit the minimum
+            // scale to 1.0f. The proper minimum scale will be calculated when
+            // the new picture shows up.
+            mMinZoomScale = Math.min(1.0f, (float) mWebView.getViewWidth()
+                    / (mWebView.drawHistory() ? mWebView.getHistoryPictureWidth()
+                            : mZoomOverviewWidth));
+            // limit the minZoomScale to the initialScale if it is set
+            if (mInitialScale > 0 && mInitialScale < mMinZoomScale) {
+                mMinZoomScale = mInitialScale;
+            }
+        }
+
+        dismissZoomPicker();
+
+        // onSizeChanged() is called during WebView layout. And any
+        // requestLayout() is blocked during layout. As refreshZoomScale() will
+        // cause its child View to reposition itself through ViewManager's
+        // scaleAll(), we need to post a Runnable to ensure requestLayout().
+        // Additionally, only update the text wrap scale if the width changed.
+        mWebView.post(new PostScale(w != ow));
+    }
+
+    private class PostScale implements Runnable {
+        final boolean mUpdateTextWrap;
+
+        public PostScale(boolean updateTextWrap) {
+            mUpdateTextWrap = updateTextWrap;
+        }
+
+        public void run() {
+            if (mWebView.getWebViewCore() != null) {
+                // we always force, in case our height changed, in which case we
+                // still want to send the notification over to webkit.
+                refreshZoomScale(mUpdateTextWrap);
+                // update the zoom buttons as the scale can be changed
+                updateZoomPicker();
+            }
+        }
+    }
+
+    public void updateZoomRange(WebViewCore.RestoreState restoreState,
+            int viewWidth, int minPrefWidth, boolean updateZoomOverview) {
+        if (restoreState.mMinScale == 0) {
+            if (restoreState.mMobileSite) {
+                if (minPrefWidth > Math.max(0, viewWidth)) {
+                    mMinZoomScale = (float) viewWidth / minPrefWidth;
+                    mMinZoomScaleFixed = false;
+                    if (updateZoomOverview) {
+                        WebSettings settings = mWebView.getSettings();
+                        mInZoomOverview = settings.getUseWideViewPort() &&
+                                settings.getLoadWithOverviewMode();
+                    }
+                } else {
+                    mMinZoomScale = restoreState.mDefaultScale;
+                    mMinZoomScaleFixed = true;
+                }
+            } else {
+                mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+                mMinZoomScaleFixed = false;
+            }
+        } else {
+            mMinZoomScale = restoreState.mMinScale;
+            mMinZoomScaleFixed = true;
+        }
+        if (restoreState.mMaxScale == 0) {
+            mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+        } else {
+            mMaxZoomScale = restoreState.mMaxScale;
+        }
+    }
+
+    /**
+     * Updates zoom values when Webkit produces a new picture. This method
+     * should only be called from the UI thread's message handler.
+     */
+    public void onNewPicture(WebViewCore.DrawData drawData) {
+
+        final int viewWidth = mWebView.getViewWidth();
+
+        if (mWebView.getSettings().getUseWideViewPort()) {
+            // limit mZoomOverviewWidth upper bound to
+            // sMaxViewportWidth so that if the page doesn't behave
+            // well, the WebView won't go insane. limit the lower
+            // bound to match the default scale for mobile sites.
+            mZoomOverviewWidth = Math.min(WebView.sMaxViewportWidth,
+                    Math.max((int) (viewWidth * mInvDefaultScale),
+                            Math.max(drawData.mMinPrefWidth,
+                                    drawData.mViewPoint.x)));
+        }
+        if (!mMinZoomScaleFixed) {
+            mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
+        }
+        if (!mWebView.drawHistory() && mInZoomOverview) {
+            // fit the content width to the current view. Ignore
+            // the rounding error case.
+            if (Math.abs((viewWidth * mInvActualScale) - mZoomOverviewWidth) > 1) {
+                setZoomScale((float) viewWidth / mZoomOverviewWidth,
+                        !willScaleTriggerZoom(mTextWrapScale));
+            }
+        }
+    }
+
+    /**
+     * Updates zoom values when Webkit restores a old picture. This method
+     * should only be called from the UI thread's message handler.
+     */
+    public void restoreZoomState(WebViewCore.DrawData drawData) {
+        // precondition check
+        assert drawData != null;
+        assert drawData.mRestoreState != null;
+        assert mWebView.getSettings() != null;
+
+        WebViewCore.RestoreState restoreState = drawData.mRestoreState;
+        final Point viewSize = drawData.mViewPoint;
+        updateZoomRange(restoreState, viewSize.x, drawData.mMinPrefWidth, true);
+
+        if (!mWebView.drawHistory()) {
+            mInZoomOverview = false;
+
+            final float scale;
+            final boolean reflowText;
+
+            if (mInitialScale > 0) {
+                scale = mInitialScale;
+                reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
+            } else if (restoreState.mViewScale > 0) {
+                mTextWrapScale = restoreState.mTextWrapScale;
+                scale = restoreState.mViewScale;
+                reflowText = false;
+            } else {
+                WebSettings settings = mWebView.getSettings();
+                mInZoomOverview = settings.getUseWideViewPort() &&
+                        settings.getLoadWithOverviewMode();
+                if (mInZoomOverview) {
+                    scale = (float) mWebView.getViewWidth() / WebView.DEFAULT_VIEWPORT_WIDTH;
+                } else {
+                    scale = restoreState.mTextWrapScale;
+                }
+                reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
+            }
+            setZoomScale(scale, reflowText);
+
+            // update the zoom buttons as the scale can be changed
+            updateZoomPicker();
+        }
+    }
+
     private ZoomControlBase getCurrentZoomControl() {
         if (mWebView.getSettings() != null && mWebView.getSettings().supportZoom()) {
             if (mWebView.getSettings().getBuiltInZoomControls()) {
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index c246c247..39b1377 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -123,7 +123,7 @@
     }
 
     private void initFloatingWindow() {
-        mWindowManager = (WindowManager)mContext.getSystemService("window");
+        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
         mWindow = PolicyManager.makeNewWindow(mContext);
         mWindow.setWindowManager(mWindowManager, null, null);
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 3003580..7a70c80 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -100,6 +100,7 @@
      * Base class for all actions that can be performed on an 
      * inflated view.
      *
+     *  SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
      */
     private abstract static class Action implements Parcelable {
         public abstract void apply(View root) throws ActionException;
@@ -568,6 +569,14 @@
         }
     }
 
+    public RemoteViews clone() {
+        final RemoteViews that = new RemoteViews(mPackage, mLayoutId);
+        if (mActions != null) {
+            that.mActions = (ArrayList<Action>)mActions.clone();
+        }
+        return that;
+    }
+
     public String getPackage() {
         return mPackage;
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3466c17..0de4f4e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4847,6 +4847,8 @@
                 break;
 
             case Gravity.RIGHT:
+                // Note, Layout resolves ALIGN_OPPOSITE to left or
+                // right based on the paragraph direction.
                 alignment = Layout.Alignment.ALIGN_OPPOSITE;
                 break;
 
@@ -5668,11 +5670,15 @@
         final int leftChar = mLayout.getOffsetForHorizontal(line, hs);
         final int rightChar = mLayout.getOffsetForHorizontal(line, hspace+hs);
         
+        // line might contain bidirectional text
+        final int lowChar = leftChar < rightChar ? leftChar : rightChar;
+        final int highChar = leftChar > rightChar ? leftChar : rightChar;
+
         int newStart = start;
-        if (newStart < leftChar) {
-            newStart = leftChar;
-        } else if (newStart > rightChar) {
-            newStart = rightChar;
+        if (newStart < lowChar) {
+            newStart = lowChar;
+        } else if (newStart > highChar) {
+            newStart = highChar;
         }
         
         if (newStart != start) {
diff --git a/core/java/com/android/internal/database/SortCursor.java b/core/java/com/android/internal/database/SortCursor.java
index 12248a2..00255128 100644
--- a/core/java/com/android/internal/database/SortCursor.java
+++ b/core/java/com/android/internal/database/SortCursor.java
@@ -218,6 +218,11 @@
     }
 
     @Override
+    public int getType(int column) {
+        return mCursor.getType(column);
+    }
+
+    @Override
     public boolean isNull(int column)
     {
         return mCursor.isNull(column);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index b677b1e..9fcd3f5 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -66,10 +66,6 @@
     /** when preloading, GC after allocating this many bytes */
     private static final int PRELOAD_GC_THRESHOLD = 50000;
 
-    /** throw on missing preload, only if this looks like a developer */
-    private static final boolean THROW_ON_MISSING_PRELOAD =
-            "1".equals(SystemProperties.get("persist.service.adb.enable"));
-
     public static final String USAGE_STRING =
             " <\"true\"|\"false\" for startSystemServer>";
 
@@ -287,7 +283,6 @@
 
                 int count = 0;
                 String line;
-                String missingClasses = null;
                 while ((line = br.readLine()) != null) {
                     // Skip comments and blank lines.
                     line = line.trim();
@@ -311,12 +306,7 @@
                         }
                         count++;
                     } catch (ClassNotFoundException e) {
-                        Log.e(TAG, "Class not found for preloading: " + line);
-                        if (missingClasses == null) {
-                            missingClasses = line;
-                        } else {
-                            missingClasses += " " + line;
-                        }
+                        Log.w(TAG, "Class not found for preloading: " + line);
                     } catch (Throwable t) {
                         Log.e(TAG, "Error preloading " + line + ".", t);
                         if (t instanceof Error) {
@@ -329,13 +319,6 @@
                     }
                 }
 
-                if (THROW_ON_MISSING_PRELOAD &&
-                    missingClasses != null) {
-                    throw new IllegalStateException(
-                            "Missing class(es) for preloading, update preloaded-classes ["
-                            + missingClasses + "]");
-                }
-
                 Log.i(TAG, "...preloaded " + count + " classes in "
                         + (SystemClock.uptimeMillis()-startTime) + "ms.");
             } catch (IOException e) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
new file mode 100644
index 0000000..4501bd7
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ 
+package com.android.internal.statusbar;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarNotification;
+
+/** @hide */
+oneway interface IStatusBar
+{
+    void setIcon(int index, in StatusBarIcon icon);
+    void removeIcon(int index);
+    void addNotification(IBinder key, in StatusBarNotification notification);
+    void updateNotification(IBinder key, in StatusBarNotification notification);
+    void removeNotification(IBinder key);
+    void disable(int state);
+    void animateExpand();
+    void animateCollapse();
+}
+
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
new file mode 100644
index 0000000..1f25b37
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ 
+package com.android.internal.statusbar;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+/** @hide */
+interface IStatusBarService
+{
+    void expand();
+    void collapse();
+    void disable(int what, IBinder token, String pkg);
+    void setIcon(String slot, String iconPackage, int iconId, int iconLevel);
+    void setIconVisibility(String slot, boolean visible);
+    void removeIcon(String slot);
+
+    // ---- Methods below are for use by the status bar policy services ----
+    void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
+            out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications);
+    void visibilityChanged(boolean visible);
+    void onNotificationClick(String pkg, String tag, int id);
+    void onClearAllNotifications();
+}
diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.aidl b/core/java/com/android/internal/statusbar/StatusBarIcon.aidl
new file mode 100644
index 0000000..311a077
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIcon.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarIcon;
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java
new file mode 100644
index 0000000..ae2cac2
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java
@@ -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.
+ */
+
+package com.android.internal.statusbar;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class StatusBarIcon implements Parcelable {
+    public String iconPackage;
+    public int iconId;
+    public int iconLevel;
+    public boolean visible = true;
+    public int number;
+
+    private StatusBarIcon() {
+    }
+
+    public StatusBarIcon(String iconPackage, int iconId, int iconLevel) {
+        this.iconPackage = iconPackage;
+        this.iconId = iconId;
+        this.iconLevel = iconLevel;
+    }
+
+    public StatusBarIcon(String iconPackage, int iconId, int iconLevel, int number) {
+        this.iconPackage = iconPackage;
+        this.iconId = iconId;
+        this.iconLevel = iconLevel;
+        this.number = number;
+    }
+
+    public String toString() {
+        return "StatusBarIcon(pkg=" + this.iconPackage + " id=0x" + Integer.toHexString(this.iconId)
+                + " level=" + this.iconLevel + " visible=" + visible
+                + " num=" + this.number + " )";
+    }
+
+    public StatusBarIcon clone() {
+        StatusBarIcon that = new StatusBarIcon(this.iconPackage, this.iconId, this.iconLevel);
+        that.visible = this.visible;
+        that.number = this.number;
+        return that;
+    }
+
+    /**
+     * Unflatten the StatusBarIcon from a parcel.
+     */
+    public StatusBarIcon(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public void readFromParcel(Parcel in) {
+        this.iconPackage = in.readString();
+        this.iconId = in.readInt();
+        this.iconLevel = in.readInt();
+        this.visible = in.readInt() != 0;
+        this.number = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(this.iconPackage);
+        out.writeInt(this.iconId);
+        out.writeInt(this.iconLevel);
+        out.writeInt(this.visible ? 1 : 0);
+        out.writeInt(this.number);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Parcelable.Creator that instantiates StatusBarIcon objects
+     */
+    public static final Parcelable.Creator<StatusBarIcon> CREATOR
+            = new Parcelable.Creator<StatusBarIcon>()
+    {
+        public StatusBarIcon createFromParcel(Parcel parcel)
+        {
+            return new StatusBarIcon(parcel);
+        }
+
+        public StatusBarIcon[] newArray(int size)
+        {
+            return new StatusBarIcon[size];
+        }
+    };
+}
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarIconList.aidl b/core/java/com/android/internal/statusbar/StatusBarIconList.aidl
new file mode 100644
index 0000000..c745120
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIconList.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarIconList;
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarIconList.java b/core/java/com/android/internal/statusbar/StatusBarIconList.java
new file mode 100644
index 0000000..478d245
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIconList.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.PrintWriter;
+
+public class StatusBarIconList implements Parcelable {
+    private String[] mSlots;
+    private StatusBarIcon[] mIcons;
+
+    public StatusBarIconList() {
+    }
+
+    public StatusBarIconList(Parcel in) {
+        readFromParcel(in);
+    }
+    
+    public void readFromParcel(Parcel in) {
+        this.mSlots = in.readStringArray();
+        final int N = in.readInt();
+        if (N < 0) {
+            mIcons = null;
+        } else {
+            mIcons = new StatusBarIcon[N];
+            for (int i=0; i<N; i++) {
+                if (in.readInt() != 0) {
+                    mIcons[i] = new StatusBarIcon(in);
+                }
+            }
+        }
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeStringArray(mSlots);
+        if (mIcons == null) {
+            out.writeInt(-1);
+        } else {
+            final int N = mIcons.length;
+            out.writeInt(N);
+            for (int i=0; i<N; i++) {
+                StatusBarIcon ic = mIcons[i];
+                if (ic == null) {
+                    out.writeInt(0);
+                } else {
+                    out.writeInt(1);
+                    ic.writeToParcel(out, flags);
+                }
+            }
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Parcelable.Creator that instantiates StatusBarIconList objects
+     */
+    public static final Parcelable.Creator<StatusBarIconList> CREATOR
+            = new Parcelable.Creator<StatusBarIconList>()
+    {
+        public StatusBarIconList createFromParcel(Parcel parcel)
+        {
+            return new StatusBarIconList(parcel);
+        }
+
+        public StatusBarIconList[] newArray(int size)
+        {
+            return new StatusBarIconList[size];
+        }
+    };
+
+    public void defineSlots(String[] slots) {
+        final int N = slots.length;
+        String[] s = mSlots = new String[N];
+        for (int i=0; i<N; i++) {
+            s[i] = slots[i];
+        }
+        mIcons = new StatusBarIcon[N];
+    }
+
+    public int getSlotIndex(String slot) {
+        final int N = mSlots.length;
+        for (int i=0; i<N; i++) {
+            if (slot.equals(mSlots[i])) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public int size() {
+        return mSlots.length;
+    }
+
+    public void setIcon(int index, StatusBarIcon icon) {
+        mIcons[index] = icon.clone();
+    }
+
+    public void removeIcon(int index) {
+        mIcons[index] = null;
+    }
+
+    public String getSlot(int index) {
+        return mSlots[index];
+    }
+
+    public StatusBarIcon getIcon(int index) {
+        return mIcons[index];
+    }
+
+    public int getViewIndex(int index) {
+        int count = 0;
+        for (int i=0; i<index; i++) {
+            if (mIcons[i] != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public void copyFrom(StatusBarIconList that) {
+        if (that.mSlots == null) {
+            this.mSlots = null;
+            this.mIcons = null;
+        } else {
+            final int N = that.mSlots.length;
+            this.mSlots = new String[N];
+            this.mIcons = new StatusBarIcon[N];
+            for (int i=0; i<N; i++) {
+                this.mSlots[i] = that.mSlots[i];
+                this.mIcons[i] = that.mIcons[i] != null ? that.mIcons[i].clone() : null;
+            }
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        final int N = mSlots.length;
+        pw.println("Icon list:");
+        for (int i=0; i<N; i++) {
+            pw.printf("  %2d: (%s) %s\n", i, mSlots[i], mIcons[i]);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.aidl b/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
new file mode 100644
index 0000000..bd9e89c
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarNotification;
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java
new file mode 100644
index 0000000..5499676
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import android.app.Notification;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+
+
+/*
+boolean clearable = !n.ongoingEvent && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
+
+
+// TODO: make this restriction do something smarter like never fill
+// more than two screens.  "Why would anyone need more than 80 characters." :-/
+final int maxTickerLen = 80;
+if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
+    truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
+}
+*/
+
+public class StatusBarNotification implements Parcelable {
+    public String pkg;
+    public int id;
+    public String tag;
+    public Notification notification;
+
+    public StatusBarNotification() {
+    }
+
+    public StatusBarNotification(String pkg, int id, String tag, Notification notification) {
+        if (pkg == null) throw new NullPointerException();
+        if (notification == null) throw new NullPointerException();
+
+        this.pkg = pkg;
+        this.id = id;
+        this.tag = tag;
+        this.notification = notification;
+    }
+
+    public StatusBarNotification(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public void readFromParcel(Parcel in) {
+        this.pkg = in.readString();
+        this.id = in.readInt();
+        if (in.readInt() != 0) {
+            this.tag = in.readString();
+        } else {
+            this.tag = null;
+        }
+        this.notification = new Notification(in);
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(this.pkg);
+        out.writeInt(this.id);
+        if (this.tag != null) {
+            out.writeInt(1);
+            out.writeString(this.tag);
+        } else {
+            out.writeInt(0);
+        }
+        this.notification.writeToParcel(out, flags);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<StatusBarNotification> CREATOR
+            = new Parcelable.Creator<StatusBarNotification>()
+    {
+        public StatusBarNotification createFromParcel(Parcel parcel)
+        {
+            return new StatusBarNotification(parcel);
+        }
+
+        public StatusBarNotification[] newArray(int size)
+        {
+            return new StatusBarNotification[size];
+        }
+    };
+
+    public StatusBarNotification clone() {
+        return new StatusBarNotification(this.pkg, this.id, this.tag, this.notification.clone());
+    }
+
+    public String toString() {
+        return "StatusBarNotification(package=" + pkg + " id=" + id + " tag=" + tag
+                + " notification=" + notification + ")";
+    }
+
+    public boolean isOngoing() {
+        return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
+    }
+
+}
+
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotificationList.aidl b/core/java/com/android/internal/statusbar/StatusBarNotificationList.aidl
new file mode 100644
index 0000000..10abeee
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarNotificationList.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarNotificationList;
+
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index fba6f0f..55f5252 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -652,6 +652,22 @@
     window->freeLastRow();
 }
 
+static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+    int32_t err;
+    CursorWindow * window = GET_WINDOW(env, object);
+    LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
+
+    field_slot_t field;
+    err = window->read_field_slot(row, column, &field);
+    if (err != 0) {
+        throwExceptionWithRowCol(env, row, column);
+        return NULL;
+    }
+
+    return field.type;
+}
+
 static JNINativeMethod sMethods[] =
 {
      /* name, signature, funcPtr */
@@ -679,6 +695,7 @@
     {"isString_native", "(II)Z", (void *)isString_native},
     {"isFloat_native", "(II)Z", (void *)isFloat_native},
     {"isInteger_native", "(II)Z", (void *)isInteger_native},
+    {"getType_native", "(II)I", (void *)getType_native},
 };
 
 int register_android_database_CursorWindow(JNIEnv * env)
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png
deleted file mode 100644
index c4e70a8..0000000
--- a/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png
deleted file mode 100644
index ac66f5a..0000000
--- a/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png
deleted file mode 100644
index 32d99c6..0000000
--- a/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
index 96dc085..7a8b78f 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
deleted file mode 100644
index 9ed20ba..0000000
--- a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png
deleted file mode 100644
index d3287db..0000000
--- a/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/battery_charge_fill.xml b/core/res/res/drawable/battery_charge_fill.xml
deleted file mode 100644
index 7f65733..0000000
--- a/core/res/res/drawable/battery_charge_fill.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="29" android:drawable="@android:drawable/battery_charge_fill_empty" />
-    <item android:maxLevel="49" android:drawable="@android:drawable/battery_charge_fill_warning" />
-    <item android:maxLevel="100" android:drawable="@android:drawable/battery_charge_fill_full" />
-</level-list>
-
diff --git a/core/res/res/layout/battery_status.xml b/core/res/res/layout/battery_status.xml
deleted file mode 100644
index 7cfec05..0000000
--- a/core/res/res/layout/battery_status.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/frame"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:gravity="center_horizontal"
-    >
-    
-    <FrameLayout
-        android:layout_width="141px" 
-        android:layout_height="184px"
-        android:background="@drawable/battery_charge_background"
-        android:paddingTop="25px"
-        android:paddingLeft="1px"
-        >
-
-        <LinearLayout
-            android:id="@+id/meter"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical"
-            >
-
-            <ImageView
-                android:layout_width="match_parent"
-                android:layout_height="15dip"
-                />
-            <ImageView
-                android:id="@+id/spacer"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                />
-            <ImageView
-                android:id="@+id/level"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-            />
-        
-        </LinearLayout>
-
-        <TextView android:id="@+id/level_percent"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:textStyle="bold"
-            android:textSize="48dp"
-            android:textColor="#ffffffff"
-            android:gravity="center"
-            />
-    </FrameLayout>
-
-    <TextView android:id="@+id/status"
-        android:paddingTop="35dp"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:textStyle="bold"
-        android:textSize="30dp"
-        android:textColor="#ffffffff"
-        android:gravity="center_horizontal"
-        android:text="@string/battery_status_charging"
-        />
-
-</LinearLayout>
-
-
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index ea6200a..c64b90e 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -12,7 +12,8 @@
         android:orientation="horizontal"
         android:paddingTop="3dp"
         >
-        <com.android.server.status.AnimatedImageView android:id="@+id/icon"
+        <!--com.android.server.status.AnimatedImageView android:id="@+id/icon" -->
+        <ImageView android:id="@+id/icon"
             android:layout_width="25dp"
             android:layout_height="25dp"
             android:scaleType="fitCenter"
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index a0bc5b3..04937565 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -120,25 +120,25 @@
     <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
     <string-array name="status_bar_icon_order">
-        <item><xliff:g id="id">clock</xliff:g></item>
-        <item><xliff:g id="id">secure</xliff:g></item>
-        <item><xliff:g id="id">alarm_clock</xliff:g></item>
-        <item><xliff:g id="id">battery</xliff:g></item>
-        <item><xliff:g id="id">phone_signal</xliff:g></item>
-        <item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
-        <item><xliff:g id="id">data_connection</xliff:g></item>
-        <item><xliff:g id="id">cdma_eri</xliff:g></item>
-        <item><xliff:g id="id">wifi</xliff:g></item>
-        <item><xliff:g id="id">tty</xliff:g></item>
-        <item><xliff:g id="id">volume</xliff:g></item>
-        <item><xliff:g id="id">mute</xliff:g></item>
-        <item><xliff:g id="id">speakerphone</xliff:g></item>
-        <item><xliff:g id="id">tty</xliff:g></item>
-        <item><xliff:g id="id">bluetooth</xliff:g></item>
-        <item><xliff:g id="id">gps</xliff:g></item>
-        <item><xliff:g id="id">sync_active</xliff:g></item>
-        <item><xliff:g id="id">sync_failing</xliff:g></item>
-        <item><xliff:g id="id">ime</xliff:g></item>
+       <item><xliff:g id="id">ime</xliff:g></item>
+       <item><xliff:g id="id">sync_failing</xliff:g></item>
+       <item><xliff:g id="id">sync_active</xliff:g></item>
+       <item><xliff:g id="id">gps</xliff:g></item>
+       <item><xliff:g id="id">bluetooth</xliff:g></item>
+       <item><xliff:g id="id">tty</xliff:g></item>
+       <item><xliff:g id="id">speakerphone</xliff:g></item>
+       <item><xliff:g id="id">mute</xliff:g></item>
+       <item><xliff:g id="id">volume</xliff:g></item>
+       <item><xliff:g id="id">tty</xliff:g></item>
+       <item><xliff:g id="id">wifi</xliff:g></item>
+       <item><xliff:g id="id">cdma_eri</xliff:g></item>
+       <item><xliff:g id="id">data_connection</xliff:g></item>
+       <item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
+       <item><xliff:g id="id">phone_signal</xliff:g></item>
+       <item><xliff:g id="id">battery</xliff:g></item>
+       <item><xliff:g id="id">alarm_clock</xliff:g></item>
+       <item><xliff:g id="id">secure</xliff:g></item>
+       <item><xliff:g id="id">clock</xliff:g></item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b4c4811..4c32ec9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -235,6 +235,10 @@
          the safe mode.  -->
     <attr name="vmSafeMode" format="boolean" />
 
+    <!-- Flag indicating whether the application's rendering should be hardware
+         accelerated if possible.  -->
+    <attr name="hardwareAccelerated" format="boolean" />
+
     <!-- Flag indicating whether the given application component is available
          to other applications.  If false, it can only be accessed by
          applications with its same user id (which usually means only by
@@ -730,6 +734,7 @@
         <attr name="enabled" />
         <attr name="debuggable" />
         <attr name="vmSafeMode" />
+        <attr name="hardwareAccelerated" />
         <!-- Name of activity to be launched for managing the application's space on the device. -->
         <attr name="manageSpaceActivity" />
         <attr name="allowClearUserData" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 64f05fe..cd47ae9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -220,9 +220,6 @@
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
 
-    <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices -->
-    <bool name="config_hspa_data_distinguishable">false</bool>
-
     <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
          The N entries of this array define N + 1 zones as follows:
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9055970..1aa55e2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1281,6 +1281,7 @@
   <public type="attr" name="displayOptions" />
   <public type="attr" name="subtitle" />
   <public type="attr" name="customNavigationLayout" />
+  <public type="attr" name="hardwareAccelerated" />
 
   <public type="id" name="home" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 61af22d..e57d0a1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1470,6 +1470,8 @@
     <string name="lockscreen_pattern_correct">Correct!</string>
     <!-- On the unlock pattern screen, shown when the user enters the wrong lock pattern and must try again. -->
     <string name="lockscreen_pattern_wrong">Sorry, try again</string>
+    <!-- On the unlock password screen, shown when the user enters the wrong lock password and must try again. -->
+    <string name="lockscreen_password_wrong">Sorry, try again</string>
 
     <!-- When the lock screen is showing and the phone plugged in, and the battery
          is not fully charged, show the current charge %.  -->
@@ -1591,45 +1593,6 @@
     <!-- A format string for 12-hour time of day, just the hour, not the minute, with capital "AM" or "PM" (example: "3PM"). -->
     <string name="hour_cap_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="PM">%p</xliff:g>"</string>
 
-    <!-- The text for the button in the notification window-shade that clears
-         all of the currently visible notifications. -->
-    <string name="status_bar_clear_all_button">Clear</string>
-
-    <!-- The label in the bar at the top of the status bar when there are no notifications
-         showing. -->
-    <string name="status_bar_no_notifications_title">No notifications</string>
-
-    <!-- The label for the group of notifications for ongoing events in the opened version of
-         the status bar.  An ongoing call is the prime example of this.  The MP3 music player
-         might be another example.  -->
-    <string name="status_bar_ongoing_events_title">Ongoing</string>
-
-    <!-- The label for the group of notifications for recent events in the opened version of
-         the status bar.  Recently received text messsages (SMS), emails, calendar alerts, etc. -->
-    <string name="status_bar_latest_events_title">Notifications</string>
-
-    <!-- The big percent text in the middle of the battery icon that appears when you plug in
-         the charger. -->
-    <string name="battery_status_text_percent_format"><xliff:g id="number" example="50">%d</xliff:g><xliff:g id="percent" example="%">%%</xliff:g></string>
-
-    <!-- The big percent text in the middle of the battery icon that appears when you plug in
-         the charger. This indicates the current status of the battery.  -->
-    <string name="battery_status_charging">Charging\u2026</string>
-
-    <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert. -->
-    <string name="battery_low_title">Please connect charger</string>
-
-    <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. -->
-    <string name="battery_low_subtitle">The battery is getting low:</string>
-
-    <!-- A message that appears when the battery level is getting low in a dialog.  This is appened to the subtitle of the low battery alert. -->
-    <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g>
-    or less remaining.</string>
-
-    <!-- When the battery is low, this is the label of the button to go to the
-         power usage activity to find out what drained the battery. -->
-    <string name="battery_low_why">Battery use</string>
-
     <!-- Title of the alert when something went wrong in the factory test. -->
     <string name="factorytest_failed">Factory test failed</string>
     <!-- Error message displayed when a non-system application tries to start a factory test. -->
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 5b427be..a5229cc 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -26,6 +26,8 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.style.StyleSpan;
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
 import android.test.MoreAsserts;
 
 import com.android.common.Rfc822Validator;
@@ -269,6 +271,24 @@
         }
     }
 
+    @SmallTest
+    public void testRfc822TokenizerFullAddress() {
+        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("Foo Bar (something) <foo@google.com>");
+        assertNotNull(tokens);
+        assertEquals(1, tokens.length);
+        assertEquals("foo@google.com", tokens[0].getAddress());
+        assertEquals("Foo Bar", tokens[0].getName());
+        assertEquals("something",tokens[0].getComment());
+    }
+
+    @SmallTest
+    public void testRfc822TokenizeItemWithError() {
+        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("\"Foo Bar\\");
+        assertNotNull(tokens);
+        assertEquals(1, tokens.length);
+        assertEquals("Foo Bar", tokens[0].getAddress());
+    }
+
     @LargeTest
     public void testEllipsize() {
         CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 74117d6..aad0f92 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -445,7 +445,7 @@
 <p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
 href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
 ExampleAgent}</a> class in the <a
-href="{@docRoot}}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
 application.</p>
 </div>
 
diff --git a/docs/html/guide/topics/security/security.jd b/docs/html/guide/topics/security/security.jd
index da201c4..dbc9866 100644
--- a/docs/html/guide/topics/security/security.jd
+++ b/docs/html/guide/topics/security/security.jd
@@ -40,15 +40,14 @@
 e-mails), reading or writing another application's files, performing
 network access, keeping the device awake, etc.<p>
 
-<p>An application's process is a secure sandbox.  It can't disrupt other
-applications, except by explicitly declaring the <em>permissions</em> it needs
-for additional capabilities not provided by the basic sandbox.  These
-permissions it requests can be handled by the operating in various ways,
-typically by automatically allowing or disallowing based on certificates or
-by prompting the user.  The permissions required by an application are declared
-statically in that application, so they can be known up-front at install time
-and will not change after that.</p>
-
+<p>An application's process runs in a security sandbox. The sandbox is designed
+to prevent applications from disrupting each other, except by explicitly
+declaring the <em>permissions</em> they need for additional capabilities not
+provided by the basic sandbox. The system handles requests for permissions
+in various ways, typically by automatically allowing or disallowing based on
+certificates or by prompting the user.  The permissions required by an
+application are declared statically in that application, so they can be known
+up-front at install time and will not change after that.</p>
 
 <a name="signing"></a>
 <h2>Application Signing</h2>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index c77e7b7..6638bef 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -50,7 +50,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.1,35.6,28.1,0.2,0.4,35.6&chl=
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.1,27.6,26.8,0.1,0.3,45.1&chl=
 Android%201.1|Android%201.5|Android%201.6|Android%202.0|Android%202.0.1|Android%202.1&chco=c4df9b,
 6fad0c" />
 
@@ -60,12 +60,12 @@
   <th>Percent of Devices</th>
 </tr>
 <tr><td>Android 1.1</td><td>0.1%</td></tr>
-<tr><td>Android 1.5</td><td>34.1%</td></tr>
-<tr><td>Android 1.6</td><td>28.0%</td></tr>
-<tr><td>Android 2.0</td><td>0.2%</td></tr>
-<tr><td>Android 2.0.1</td><td>0.4%</td></tr>
-<tr><td>Android 2.1</td><td>37.2%</td></tr>
+<tr><td>Android 1.5</td><td>27.6%</td></tr>
+<tr><td>Android 1.6</td><td>26.8%</td></tr>
+<tr><td>Android 2.0</td><td>0.1%</td></tr>
+<tr><td>Android 2.0.1</td><td>0.3%</td></tr>
+<tr><td>Android 2.1</td><td>45.1%</td></tr>
 </table>
-<p><em>Data collected during two weeks ending on May 17, 2010</em></p>
+<p><em>Data collected during two weeks ending on June 1, 2010</em></p>
 </div>
 
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index 4ce7596..5da217b 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -49,7 +49,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.0,63.9,35.1&chl=Small%20/%20ldpi|
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.0,61.6,37.4&chl=Small%20/%20ldpi|
 Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
 
 <table>
@@ -66,8 +66,8 @@
 </tr> 
 <tr><th scope="row">Normal</th> 
 <td></td> 
-<td class='cent hi'>63.7%</td> 
-<td class='cent hi'>35.3%</td> 
+<td class='cent hi'>61.3%</td> 
+<td class='cent hi'>37.7%</td> 
 </tr> 
 <tr><th scope="row">Large</th> 
 <td></td> 
@@ -76,6 +76,6 @@
 </tr> 
 </table>
 
-<p><em>Data collected during two weeks ending on May 17, 2010</em></p>
+<p><em>Data collected during two weeks ending on June 1, 2010</em></p>
 </div>
 
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index 107c604..52689b6 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -29,7 +29,7 @@
           </a></li>
       <li><a href="<?cs var:toroot ?>resources/dashboard/screens.html">
             <span class="en">Screen Sizes &amp; Densities</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
     </ul>
   </li><?cs
   /if
diff --git a/docs/html/resources/tutorials/views/hello-webview.jd b/docs/html/resources/tutorials/views/hello-webview.jd
index 17b2646..2d07647 100644
--- a/docs/html/resources/tutorials/views/hello-webview.jd
+++ b/docs/html/resources/tutorials/views/hello-webview.jd
@@ -12,7 +12,7 @@
    <li>Open the <code>res/layout/main.xml</code> file and insert the following:
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
-&lt;WebView
+&lt;WebView  xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/webview"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
@@ -79,7 +79,7 @@
   </li>
   <li>Then towards the end of the {@link android.app.Activity#onCreate(Bundle)} method, set an
   instance of the <code>HelloWebViewClient</code> as the {@link android.webkit.WebViewClient}:
-   <pre>mWebView.setWebViewClient(new WebViewClientDemo());</pre>
+   <pre>mWebView.setWebViewClient(new HelloWebViewClient());</pre>
 
     <p>This line can go anywhere following the initialization of the {@link
     android.webkit.WebView} object.</p>
diff --git a/docs/html/shareables/adl/2Q10_Business_Overview.pdf b/docs/html/shareables/adl/2010Q2_Business_Overview.pdf
similarity index 100%
rename from docs/html/shareables/adl/2Q10_Business_Overview.pdf
rename to docs/html/shareables/adl/2010Q2_Business_Overview.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2Q10_Market_Overview.pdf b/docs/html/shareables/adl/2010Q2_Market_Overview.pdf
similarity index 100%
rename from docs/html/shareables/adl/2Q10_Market_Overview.pdf
rename to docs/html/shareables/adl/2010Q2_Market_Overview.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2Q10_SDK_Overview.pdf b/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf
similarity index 100%
rename from docs/html/shareables/adl/2Q10_SDK_Overview.pdf
rename to docs/html/shareables/adl/2010Q2_SDK_Overview.pdf
Binary files differ
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index f801794..974a36e 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -91,109 +91,109 @@
         }
     }
 
-    public static Element USER_U8(RenderScript rs) {
-        if(rs.mElement_USER_U8 == null) {
-            rs.mElement_USER_U8 = createUser(rs, DataType.UNSIGNED_8);
+    public static Element U8(RenderScript rs) {
+        if(rs.mElement_U8 == null) {
+            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
         }
-        return rs.mElement_USER_U8;
+        return rs.mElement_U8;
     }
 
-    public static Element USER_I8(RenderScript rs) {
-        if(rs.mElement_USER_I8 == null) {
-            rs.mElement_USER_I8 = createUser(rs, DataType.SIGNED_8);
+    public static Element I8(RenderScript rs) {
+        if(rs.mElement_I8 == null) {
+            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
         }
-        return rs.mElement_USER_I8;
+        return rs.mElement_I8;
     }
 
-    public static Element USER_U32(RenderScript rs) {
-        if(rs.mElement_USER_U32 == null) {
-            rs.mElement_USER_U32 = createUser(rs, DataType.UNSIGNED_32);
+    public static Element U32(RenderScript rs) {
+        if(rs.mElement_U32 == null) {
+            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
         }
-        return rs.mElement_USER_U32;
+        return rs.mElement_U32;
     }
 
-    public static Element USER_I32(RenderScript rs) {
-        if(rs.mElement_USER_I32 == null) {
-            rs.mElement_USER_I32 = createUser(rs, DataType.SIGNED_32);
+    public static Element I32(RenderScript rs) {
+        if(rs.mElement_I32 == null) {
+            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
         }
-        return rs.mElement_USER_I32;
+        return rs.mElement_I32;
     }
 
-    public static Element USER_F32(RenderScript rs) {
-        if(rs.mElement_USER_F32 == null) {
-            rs.mElement_USER_F32 = createUser(rs, DataType.FLOAT_32);
+    public static Element F32(RenderScript rs) {
+        if(rs.mElement_F32 == null) {
+            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
         }
-        return rs.mElement_USER_F32;
+        return rs.mElement_F32;
     }
 
-    public static Element USER_ELEMENT(RenderScript rs) {
-        if(rs.mElement_USER_ELEMENT == null) {
-            rs.mElement_USER_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
+    public static Element ELEMENT(RenderScript rs) {
+        if(rs.mElement_ELEMENT == null) {
+            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
         }
-        return rs.mElement_USER_ELEMENT;
+        return rs.mElement_ELEMENT;
     }
 
-    public static Element USER_TYPE(RenderScript rs) {
-        if(rs.mElement_USER_TYPE == null) {
-            rs.mElement_USER_TYPE = createUser(rs, DataType.RS_TYPE);
+    public static Element TYPE(RenderScript rs) {
+        if(rs.mElement_TYPE == null) {
+            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
         }
-        return rs.mElement_USER_TYPE;
+        return rs.mElement_TYPE;
     }
 
-    public static Element USER_ALLOCATION(RenderScript rs) {
-        if(rs.mElement_USER_ALLOCATION == null) {
-            rs.mElement_USER_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
+    public static Element ALLOCATION(RenderScript rs) {
+        if(rs.mElement_ALLOCATION == null) {
+            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
         }
-        return rs.mElement_USER_ALLOCATION;
+        return rs.mElement_ALLOCATION;
     }
 
-    public static Element USER_SAMPLER(RenderScript rs) {
-        if(rs.mElement_USER_SAMPLER == null) {
-            rs.mElement_USER_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
+    public static Element SAMPLER(RenderScript rs) {
+        if(rs.mElement_SAMPLER == null) {
+            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
         }
-        return rs.mElement_USER_SAMPLER;
+        return rs.mElement_SAMPLER;
     }
 
-    public static Element USER_SCRIPT(RenderScript rs) {
-        if(rs.mElement_USER_SCRIPT == null) {
-            rs.mElement_USER_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
+    public static Element SCRIPT(RenderScript rs) {
+        if(rs.mElement_SCRIPT == null) {
+            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
         }
-        return rs.mElement_USER_SCRIPT;
+        return rs.mElement_SCRIPT;
     }
 
-    public static Element USER_MESH(RenderScript rs) {
-        if(rs.mElement_USER_MESH == null) {
-            rs.mElement_USER_MESH = createUser(rs, DataType.RS_MESH);
+    public static Element MESH(RenderScript rs) {
+        if(rs.mElement_MESH == null) {
+            rs.mElement_MESH = createUser(rs, DataType.RS_MESH);
         }
-        return rs.mElement_USER_MESH;
+        return rs.mElement_MESH;
     }
 
-    public static Element USER_PROGRAM_FRAGMENT(RenderScript rs) {
-        if(rs.mElement_USER_PROGRAM_FRAGMENT == null) {
-            rs.mElement_USER_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
+    public static Element PROGRAM_FRAGMENT(RenderScript rs) {
+        if(rs.mElement_PROGRAM_FRAGMENT == null) {
+            rs.mElement_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
         }
-        return rs.mElement_USER_PROGRAM_FRAGMENT;
+        return rs.mElement_PROGRAM_FRAGMENT;
     }
 
-    public static Element USER_PROGRAM_VERTEX(RenderScript rs) {
-        if(rs.mElement_USER_PROGRAM_VERTEX == null) {
-            rs.mElement_USER_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
+    public static Element PROGRAM_VERTEX(RenderScript rs) {
+        if(rs.mElement_PROGRAM_VERTEX == null) {
+            rs.mElement_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
         }
-        return rs.mElement_USER_PROGRAM_VERTEX;
+        return rs.mElement_PROGRAM_VERTEX;
     }
 
-    public static Element USER_PROGRAM_RASTER(RenderScript rs) {
-        if(rs.mElement_USER_PROGRAM_RASTER == null) {
-            rs.mElement_USER_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
+    public static Element PROGRAM_RASTER(RenderScript rs) {
+        if(rs.mElement_PROGRAM_RASTER == null) {
+            rs.mElement_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
         }
-        return rs.mElement_USER_PROGRAM_RASTER;
+        return rs.mElement_PROGRAM_RASTER;
     }
 
-    public static Element USER_PROGRAM_STORE(RenderScript rs) {
-        if(rs.mElement_USER_PROGRAM_STORE == null) {
-            rs.mElement_USER_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
+    public static Element PROGRAM_STORE(RenderScript rs) {
+        if(rs.mElement_PROGRAM_STORE == null) {
+            rs.mElement_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
         }
-        return rs.mElement_USER_PROGRAM_STORE;
+        return rs.mElement_PROGRAM_STORE;
     }
 
 
@@ -246,47 +246,34 @@
         return rs.mElement_INDEX_16;
     }
 
-    public static Element ATTRIB_POSITION_2(RenderScript rs) {
-        if(rs.mElement_POSITION_2 == null) {
-            rs.mElement_POSITION_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 2);
+    public static Element F32_2(RenderScript rs) {
+        if(rs.mElement_FLOAT_2 == null) {
+            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
         }
-        return rs.mElement_POSITION_2;
+        return rs.mElement_FLOAT_2;
     }
 
-    public static Element ATTRIB_POSITION_3(RenderScript rs) {
-        if(rs.mElement_POSITION_3 == null) {
-            rs.mElement_POSITION_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 3);
+    public static Element F32_3(RenderScript rs) {
+        if(rs.mElement_FLOAT_3 == null) {
+            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
         }
-        return rs.mElement_POSITION_3;
+        return rs.mElement_FLOAT_3;
     }
 
-    public static Element ATTRIB_TEXTURE_2(RenderScript rs) {
-        if(rs.mElement_TEXTURE_2 == null) {
-            rs.mElement_TEXTURE_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.TEXTURE, 2);
+    public static Element F32_4(RenderScript rs) {
+        if(rs.mElement_FLOAT_4 == null) {
+            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
         }
-        return rs.mElement_TEXTURE_2;
+        return rs.mElement_FLOAT_4;
     }
 
-    public static Element ATTRIB_NORMAL_3(RenderScript rs) {
-        if(rs.mElement_NORMAL_3 == null) {
-            rs.mElement_NORMAL_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.NORMAL, 3);
+    public static Element U8_4(RenderScript rs) {
+        if(rs.mElement_UCHAR_4 == null) {
+            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
         }
-        return rs.mElement_NORMAL_3;
+        return rs.mElement_UCHAR_4;
     }
 
-    public static Element ATTRIB_COLOR_U8_4(RenderScript rs) {
-        if(rs.mElement_COLOR_U8_4 == null) {
-            rs.mElement_COLOR_U8_4 = createAttrib(rs, DataType.UNSIGNED_8, DataKind.COLOR, 4);
-        }
-        return rs.mElement_COLOR_U8_4;
-    }
-
-    public static Element ATTRIB_COLOR_F32_4(RenderScript rs) {
-        if(rs.mElement_COLOR_F32_4 == null) {
-            rs.mElement_COLOR_F32_4 = createAttrib(rs, DataType.FLOAT_32, DataKind.COLOR, 4);
-        }
-        return rs.mElement_COLOR_F32_4;
-    }
 
     Element(RenderScript rs, Element[] e, String[] n) {
         super(rs);
@@ -331,55 +318,6 @@
         return new Element(rs, DataType.UNSIGNED_16, DataKind.INDEX, false, 1);
     }
 
-    public static Element createAttrib(RenderScript rs, DataType dt, DataKind dk, int size) {
-        if (!(dt == DataType.FLOAT_32 ||
-              dt == DataType.UNSIGNED_8 ||
-              dt == DataType.UNSIGNED_16 ||
-              dt == DataType.UNSIGNED_32 ||
-              dt == DataType.SIGNED_8 ||
-              dt == DataType.SIGNED_16 ||
-              dt == DataType.SIGNED_32)) {
-            throw new IllegalArgumentException("Unsupported DataType");
-        }
-
-        if (!(dk == DataKind.COLOR ||
-              dk == DataKind.POSITION ||
-              dk == DataKind.TEXTURE ||
-              dk == DataKind.NORMAL ||
-              dk == DataKind.POINT_SIZE ||
-              dk == DataKind.USER)) {
-            throw new IllegalArgumentException("Unsupported DataKind");
-        }
-
-        if (dk == DataKind.COLOR &&
-            ((dt != DataType.FLOAT_32 && dt != DataType.UNSIGNED_8) ||
-             size < 3 || size > 4)) {
-            throw new IllegalArgumentException("Bad combo");
-        }
-        if (dk == DataKind.POSITION && (size < 1 || size > 4)) {
-            throw new IllegalArgumentException("Bad combo");
-        }
-        if (dk == DataKind.TEXTURE &&
-            (dt != DataType.FLOAT_32 || size < 1 || size > 4)) {
-            throw new IllegalArgumentException("Bad combo");
-        }
-        if (dk == DataKind.NORMAL &&
-            (dt != DataType.FLOAT_32 || size != 3)) {
-            throw new IllegalArgumentException("Bad combo");
-        }
-        if (dk == DataKind.POINT_SIZE &&
-            (dt != DataType.FLOAT_32 || size != 1)) {
-            throw new IllegalArgumentException("Bad combo");
-        }
-
-        boolean norm = false;
-        if (dk == DataKind.COLOR && dt == DataType.UNSIGNED_8) {
-            norm = true;
-        }
-
-        return new Element(rs, dt, dk, norm, size);
-    }
-
     public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
         if (!(dk == DataKind.PIXEL_L ||
               dk == DataKind.PIXEL_A ||
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index acc58bc..eda849e 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -192,24 +192,24 @@
     @SuppressWarnings({"FieldCanBeLocal"})
     protected MessageThread mMessageThread;
 
-    Element mElement_USER_U8;
-    Element mElement_USER_I8;
-    Element mElement_USER_U16;
-    Element mElement_USER_I16;
-    Element mElement_USER_U32;
-    Element mElement_USER_I32;
-    Element mElement_USER_F32;
+    Element mElement_U8;
+    Element mElement_I8;
+    Element mElement_U16;
+    Element mElement_I16;
+    Element mElement_U32;
+    Element mElement_I32;
+    Element mElement_F32;
 
-    Element mElement_USER_ELEMENT;
-    Element mElement_USER_TYPE;
-    Element mElement_USER_ALLOCATION;
-    Element mElement_USER_SAMPLER;
-    Element mElement_USER_SCRIPT;
-    Element mElement_USER_MESH;
-    Element mElement_USER_PROGRAM_FRAGMENT;
-    Element mElement_USER_PROGRAM_VERTEX;
-    Element mElement_USER_PROGRAM_RASTER;
-    Element mElement_USER_PROGRAM_STORE;
+    Element mElement_ELEMENT;
+    Element mElement_TYPE;
+    Element mElement_ALLOCATION;
+    Element mElement_SAMPLER;
+    Element mElement_SCRIPT;
+    Element mElement_MESH;
+    Element mElement_PROGRAM_FRAGMENT;
+    Element mElement_PROGRAM_VERTEX;
+    Element mElement_PROGRAM_RASTER;
+    Element mElement_PROGRAM_STORE;
 
     Element mElement_A_8;
     Element mElement_RGB_565;
@@ -219,12 +219,10 @@
     Element mElement_RGBA_8888;
 
     Element mElement_INDEX_16;
-    Element mElement_POSITION_2;
-    Element mElement_POSITION_3;
-    Element mElement_TEXTURE_2;
-    Element mElement_NORMAL_3;
-    Element mElement_COLOR_U8_4;
-    Element mElement_COLOR_F32_4;
+    Element mElement_FLOAT_2;
+    Element mElement_FLOAT_3;
+    Element mElement_FLOAT_4;
+    Element mElement_UCHAR_4;
 
     Sampler mSampler_CLAMP_NEAREST;
     Sampler mSampler_CLAMP_LINEAR;
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index 4a217a9..fc011b5 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -313,30 +313,20 @@
         public SimpleMesh create() {
             Element.Builder b = new Element.Builder(mRS);
             int floatCount = mVtxSize;
-            b.add(Element.createAttrib(mRS,
+            b.add(Element.createVector(mRS,
                                        Element.DataType.FLOAT_32,
-                                       Element.DataKind.POSITION,
                                        mVtxSize), "position");
             if ((mFlags & COLOR) != 0) {
                 floatCount += 4;
-                b.add(Element.createAttrib(mRS,
-                                           Element.DataType.FLOAT_32,
-                                           Element.DataKind.COLOR,
-                                           4), "color");
+                b.add(Element.F32_4(mRS), "color");
             }
             if ((mFlags & TEXTURE_0) != 0) {
                 floatCount += 2;
-                b.add(Element.createAttrib(mRS,
-                                           Element.DataType.FLOAT_32,
-                                           Element.DataKind.TEXTURE,
-                                           2), "texture");
+                b.add(Element.F32_2(mRS), "texture0");
             }
             if ((mFlags & NORMAL) != 0) {
                 floatCount += 3;
-                b.add(Element.createAttrib(mRS,
-                                           Element.DataType.FLOAT_32,
-                                           Element.DataKind.NORMAL,
-                                           3), "normal");
+                b.add(Element.F32_3(mRS), "normal");
             }
             mElement = b.create();
 
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index bda0d31..4fbff2a 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -1,16 +1,16 @@
 /*
  * Copyright (C) 2006 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 
+ * 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 
+ *      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 
+ * 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.
  */
 
@@ -80,11 +80,11 @@
     } data;
 } __attribute__((packed)) field_slot_t;
 
+#define FIELD_TYPE_NULL 0
 #define FIELD_TYPE_INTEGER 1
 #define FIELD_TYPE_FLOAT 2
 #define FIELD_TYPE_STRING 3
 #define FIELD_TYPE_BLOB 4
-#define FIELD_TYPE_NULL 5
 
 /**
  * This class stores a set of rows from a database in a buffer. The begining of the
@@ -170,7 +170,7 @@
     row_slot_t *        allocRowSlot();
 
     row_slot_t *        getRowSlot(int row);
-    
+
                         /**
                          * return NULL if Failed to find rowSlot or
                          * Invalid rowSlot
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 2b7a86eb..e12a694 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -250,6 +250,13 @@
     // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
     static const char KEY_VIDEO_FRAME_FORMAT[];
 
+    // Metering mode. This affects how camera determines exposure.
+    // Example value: "spot" or METERING_MODE_XXX constants. Read/write.
+    static const char KEY_METERING_MODE[];
+    // Supported metering modes.
+    // Example value: "center-weighted,frame-average,spot". Read only.
+    static const char KEY_SUPPORTED_METERING_MODES[];
+
     // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
     static const char TRUE[];
 
@@ -347,6 +354,15 @@
     // callback will be only called once as soon as the picture is in focus.
     static const char FOCUS_MODE_CONTINUOUS[];
 
+    // The camera determines the exposure by giving more weight to the
+    // central part of the scene.
+    static const char METERING_MODE_CENTER_WEIGHTED[];
+    // The camera determines the exposure by averaging the entire scene,
+    // giving no weighting to any particular area.
+    static const char METERING_MODE_FRAME_AVERAGE[];
+    // The camera determines the exposure by a very small area of the scene,
+    // typically the center.
+    static const char METERING_MODE_SPOT[];
 
 private:
     DefaultKeyedVector<String8,String8>    mMap;
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 92bc126..d956882 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -142,7 +142,8 @@
                                     uint32_t flags      = 0,
                                     callback_t cbf = 0,
                                     void* user = 0,
-                                    int notificationFrames = 0);
+                                    int notificationFrames = 0,
+                                    int sessionId = 0);
 
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
@@ -168,7 +169,8 @@
                             callback_t cbf = 0,
                             void* user = 0,
                             int notificationFrames = 0,
-                            bool threadCanCallJava = false);
+                            bool threadCanCallJava = false,
+                            int sessionId = 0);
 
 
     /* Result of constructing the AudioRecord. This must be checked
@@ -270,6 +272,16 @@
      */
             audio_io_handle_t    getInput();
 
+    /* returns the audio session ID associated to this AudioRecord.
+     *
+     * Parameters:
+     *  none.
+     *
+     * Returned value:
+     *  AudioRecord session ID.
+     */
+            int    getSessionId();
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -356,6 +368,7 @@
     uint32_t                mFlags;
     uint32_t                mChannels;
     audio_io_handle_t       mInput;
+    int                     mSessionId;
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 9caef8f..f21e83d 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -230,6 +230,8 @@
     static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream = DEFAULT);
 
     static unsigned int  getInputFramesLost(audio_io_handle_t ioHandle);
+
+    static int newAudioSessionId();
     //
     // AudioPolicyService interface
     //
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index cc4ab74..c46df1e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -138,7 +138,8 @@
                                     uint32_t flags       = 0,
                                     callback_t cbf       = 0,
                                     void* user           = 0,
-                                    int notificationFrames = 0);
+                                    int notificationFrames = 0,
+                                    int sessionId = 0);
 
     /* Creates an audio track and registers it with AudioFlinger. With this constructor,
      * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
@@ -157,7 +158,8 @@
                                     uint32_t flags      = 0,
                                     callback_t cbf      = 0,
                                     void* user          = 0,
-                                    int notificationFrames = 0);
+                                    int notificationFrames = 0,
+                                    int sessionId = 0);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources assotiated with the AudioTrack.
@@ -182,7 +184,8 @@
                             void* user          = 0,
                             int notificationFrames = 0,
                             const sp<IMemory>& sharedBuffer = 0,
-                            bool threadCanCallJava = false);
+                            bool threadCanCallJava = false,
+                            int sessionId = 0);
 
 
     /* Result of constructing the AudioTrack. This must be checked
@@ -239,10 +242,17 @@
 
 
     /* set volume for this track, mostly used for games' sound effects
+     * left and right volumes. Levels must be <= 1.0.
      */
-            void        setVolume(float left, float right);
+            status_t    setVolume(float left, float right);
             void        getVolume(float* left, float* right);
 
+    /* set the send level for this track. An auxiliary effect should be attached
+     * to the track with attachEffect(). Level must be <= 1.0.
+     */
+            status_t    setSendLevel(float level);
+            void        getSendLevel(float* level);
+
     /* set sample rate for this track, mostly used for games' sound effects
      */
             status_t    setSampleRate(int sampleRate);
@@ -340,6 +350,31 @@
      */
             audio_io_handle_t    getOutput();
 
+    /* returns the unique ID associated to this track.
+     *
+     * Parameters:
+     *  none.
+     *
+     * Returned value:
+     *  AudioTrack ID.
+     */
+            int    getSessionId();
+
+
+    /* Attach track auxiliary output to specified effect. Used effectId = 0
+     * to detach track from effect.
+     *
+     * Parameters:
+     *
+     * effectId:  effectId obtained from AudioEffect::id().
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the effect is not an auxiliary effect.
+     *  - BAD_VALUE: The specified effect ID is invalid
+     */
+            status_t    attachAuxEffect(int effectId);
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -406,6 +441,7 @@
     sp<AudioTrackThread>    mAudioTrackThread;
 
     float                   mVolume[2];
+    float                   mSendLevel;
     uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
@@ -431,6 +467,7 @@
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
     uint32_t                mFlags;
+    int                     mSessionId;
 };
 
 
diff --git a/include/media/EffectApi.h b/include/media/EffectApi.h
index a1bc3b82..97874f7 100644
--- a/include/media/EffectApi.h
+++ b/include/media/EffectApi.h
@@ -114,7 +114,8 @@
 //  +---------------------------+-----------+-----------------------------------
 //  | Volume management         | 5..6      | 0 none
 //  |                           |           | 1 implements volume control
-//  |                           |           | 2..3 reserved
+//  |                           |           | 2 requires volume indication
+//  |                           |           | 3 reserved
 //  +---------------------------+-----------+-----------------------------------
 //  | Device management         | 7..8      | 0 none
 //  |                           |           | 1 requires device updates
@@ -154,6 +155,7 @@
 // volume control
 #define EFFECT_FLAG_VOLUME_MASK         0x00000060
 #define EFFECT_FLAG_VOLUME_CTRL         0x00000020
+#define EFFECT_FLAG_VOLUME_IND          0x00000040
 #define EFFECT_FLAG_VOLUME_NONE         0x00000000
 
 // device control
@@ -296,10 +298,12 @@
 //  | Set and get volume. Used by    | EFFECT_CMD_SET_VOLUME         | size: n * sizeof(uint32_t)    | size: n * sizeof(uint32_t)
 //  | audio framework to delegate    |                               | data: volume for each channel | data: volume for each channel
 //  | volume control to effect engine|                               | defined in effect_config_t in | defined in effect_config_t in
-//  | The engine must return the     |                               | 8.24 fixed point format       | 8.24 fixed point format
-//  | volume that should be applied  |                               |                               |
-//  | before the effect is processed |                               |                               |
-//  | The overall volume (the volume |                               |                               |
+//  | If volume control flag is set  |                               | 8.24 fixed point format       | 8.24 fixed point format
+//  | in the effect descriptor, the  |                               |                               | It is legal to receive a null
+//  | effect engine must return the  |                               |                               | pointer as pReplyData in which
+//  | volume that should be applied  |                               |                               | case the effect framework has
+//  | before the effect is processed |                               |                               | delegated volume control to
+//  | The overall volume (the volume |                               |                               | another effect.
 //  | actually applied by the effect |                               |                               |
 //  | multiplied by the returned     |                               |                               |
 //  | value) should match the        |                               |                               |
@@ -370,7 +374,7 @@
 // structure that defines both input and output buffer configurations and is
 // passed by the EFFECT_CMD_CONFIGURE command.
 typedef struct buffer_config_s {
-    audio_buffer_t  buffer;     // buffer for use by process() function is not passed explicitly
+    audio_buffer_t  buffer;     // buffer for use by process() function if not passed explicitly
     uint32_t   samplingRate;    // sampling rate
     uint32_t   channels;        // channel mask (see audio_channels_e in AudioCommon.h)
     buffer_provider_t bufferProvider;   // buffer provider
@@ -457,7 +461,7 @@
 //
 //    Function:       EffectQueryNumberEffects
 //
-//    Description:    Returns the number of different effect exposed by the
+//    Description:    Returns the number of different effects exposed by the
 //          library. Each effect must have a unique effect uuid (see
 //          effect_descriptor_t). This function together with EffectQueryNext()
 //          is used to enumerate all effects present in the library.
@@ -475,7 +479,7 @@
 //        *pNumEffects:     updated with number of effects in library
 //
 ////////////////////////////////////////////////////////////////////////////////
-typedef int32_t (*effect_QueryNumberEffects_t)(int32_t *pNumEffects);
+typedef int32_t (*effect_QueryNumberEffects_t)(uint32_t *pNumEffects);
 
 ////////////////////////////////////////////////////////////////////////////////
 //
@@ -521,7 +525,7 @@
 //        returned value:    0          successful operation.
 //                          -ENODEV     library failed to initialize
 //                          -EINVAL     invalid pEffectUuid or pInterface
-//                          -ENOENT     No effect with this uuid found
+//                          -ENOENT     no effect with this uuid found
 //        *pInterface:     updated with the effect interface handle.
 //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/media/EffectFactoryApi.h b/include/media/EffectFactoryApi.h
index 8179c234..6cc9932 100644
--- a/include/media/EffectFactoryApi.h
+++ b/include/media/EffectFactoryApi.h
@@ -34,7 +34,7 @@
 //
 //    Function:       EffectQueryNumberEffects
 //
-//    Description:    Returns the number of different effect in all loaded libraries.
+//    Description:    Returns the number of different effects in all loaded libraries.
 //          Each effect must have a different effect uuid (see
 //          effect_descriptor_t). This function together with EffectQueryNext()
 //          is used to enumerate all effects present in all loaded libraries.
@@ -52,7 +52,7 @@
 //        *pNumEffects:     updated with number of effects in factory
 //
 ////////////////////////////////////////////////////////////////////////////////
-int EffectQueryNumberEffects(int *pNumEffects);
+int EffectQueryNumberEffects(uint32_t *pNumEffects);
 
 ////////////////////////////////////////////////////////////////////////////////
 //
@@ -98,7 +98,7 @@
 //        returned value:    0          successful operation.
 //                          -ENODEV     factory failed to initialize
 //                          -EINVAL     invalid pEffectUuid or pInterface
-//                          -ENOENT     No effect with this uuid found
+//                          -ENOENT     no effect with this uuid found
 //        *pInterface:     updated with the effect interface.
 //
 ////////////////////////////////////////////////////////////////////////////////
@@ -140,7 +140,7 @@
 //
 //    Output:
 //        returned value:    0          successful operation.
-//                          -ENODEV     Effect factory not initialized or
+//                          -ENODEV     effect factory not initialized or
 //                                      library could not be loaded or
 //                                      library does not implement required functions
 //                          -EINVAL     invalid libPath string or handle
@@ -159,7 +159,7 @@
 //
 //    Output:
 //        returned value:    0          successful operation.
-//                          -ENODEV     Effect factory not initialized
+//                          -ENODEV     effect factory not initialized
 //                          -ENOENT     invalid handle
 //
 ////////////////////////////////////////////////////////////////////////////////
@@ -184,7 +184,7 @@
 //        returned value:    0          successful operation.
 //                          -ENODEV     factory failed to initialize
 //                          -EINVAL     invalid pEffectUuid or pDescriptor
-//                          -ENOENT     No effect with this uuid found
+//                          -ENOENT     no effect with this uuid found
 //        *pDescriptor:     updated with the effect descriptor.
 //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index c147632..ccfa530 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -27,6 +27,9 @@
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/IAudioFlingerClient.h>
+#include <media/EffectApi.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -51,6 +54,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 int output,
+                                int *sessionId,
                                 status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
@@ -61,6 +65,7 @@
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
+                                int *sessionId,
                                 status_t *status) = 0;
 
     /* query the audio hardware state. This state never changes,
@@ -134,6 +139,28 @@
     virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
 
     virtual unsigned int  getInputFramesLost(int ioHandle) = 0;
+
+    virtual int newAudioSessionId() = 0;
+
+    virtual status_t loadEffectLibrary(const char *libPath, int *handle) = 0;
+
+    virtual status_t unloadEffectLibrary(int handle) = 0;
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
+
+    virtual status_t queryNextEffect(effect_descriptor_t *pDescriptor) = 0;
+
+    virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0;
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                                    effect_descriptor_t *pDesc,
+                                    const sp<IEffectClient>& client,
+                                    int32_t priority,
+                                    int output,
+                                    int sessionId,
+                                    status_t *status,
+                                    int *id,
+                                    int *enabled) = 0;
 };
 
 
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index de6426a..47d530b 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -62,6 +62,11 @@
      */
     virtual void        pause() = 0;
 
+    /* Attach track auxiliary output to specified effect. Use effectId = 0
+     * to detach track from effect.
+     */
+    virtual status_t    attachAuxEffect(int effectId) = 0;
+
     /* get this tracks control block */
     virtual sp<IMemory> getCblk() const = 0;    
 };
diff --git a/include/private/media/AudioEffectShared.h b/include/private/media/AudioEffectShared.h
new file mode 100644
index 0000000..a3a99a4
--- /dev/null
+++ b/include/private/media/AudioEffectShared.h
@@ -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.
+ */
+
+#ifndef ANDROID_EFFECTCBASESHARED_H
+#define ANDROID_EFFECTCBASESHARED_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// Size of buffer used to exchange parameters between application and mediaserver processes.
+#define EFFECT_PARAM_BUFFER_SIZE 1024
+
+
+// Shared memory area used to exchange parameters between application and mediaserver
+// process.
+struct effect_param_cblk_t
+{
+                Mutex       lock;
+    volatile    uint32_t    clientIndex;    // Current read/write index for application
+    volatile    uint32_t    serverIndex;    // Current read/write index for mediaserver
+                uint8_t*    buffer;         // start of parameter buffer
+
+                effect_param_cblk_t()
+                    : lock(Mutex::SHARED), clientIndex(0), serverIndex(0) {}
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_EFFECTCBASESHARED_H
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index cd47fdf..1510f87 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -78,7 +78,8 @@
                 uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
                 uint16_t    waitTimeMs;      // Cumulated wait time
 
-                uint32_t    reserved;
+                uint16_t    sendLevel;
+                uint16_t    reserved;
                 // Cache line boundary (32 bytes)
                             audio_track_cblk_t();
                 uint32_t    stepUser(uint32_t frameCount);
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index b859e78..dcce25e 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -136,9 +136,7 @@
 public:
     SharedClient();
     ~SharedClient();
-
     status_t validate(size_t token) const;
-    uint32_t getIdentity(size_t token) const;
 
 private:
     friend class SharedBufferBase;
@@ -160,6 +158,7 @@
             int32_t identity);
     ~SharedBufferBase();
     status_t getStatus() const;
+    int32_t getIdentity() const;
     size_t getFrontBuffer() const;
     String8 dump(char const* prefix) const;
 
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index 18e7950..ddbe03d 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -53,10 +53,24 @@
 public: 
     DECLARE_META_INTERFACE(Surface);
 
+    /*
+     * requests a new buffer for the given index. If w, h, or format are
+     * null the buffer is created with the parameters assigned to the
+     * surface it is bound to. Otherwise the buffer's parameters are
+     * set to those specified.
+     */
     virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
             uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
+
+    /*
+     * sets the number of buffers dequeuable for this surface.
+     */
     virtual status_t setBufferCount(int bufferCount) = 0;
     
+    // ------------------------------------------------------------------------
+    // Deprecated...
+    // ------------------------------------------------------------------------
+
     class BufferHeap {
     public:
         enum {
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index d1e7785..3271cfd 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -27,7 +27,7 @@
 
 #include <ui/PixelFormat.h>
 
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 
 namespace android {
 // ----------------------------------------------------------------------------
@@ -86,7 +86,7 @@
      * ACCESS_SURFACE_FLINGER permission
      */
 
-    virtual sp<ISurfaceFlingerClient> createConnection() = 0;
+    virtual sp<ISurfaceComposerClient> createConnection() = 0;
 
     /* retrieve the control block */
     virtual sp<IMemoryHeap> getCblk() const = 0;
diff --git a/include/surfaceflinger/ISurfaceFlingerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
similarity index 86%
rename from include/surfaceflinger/ISurfaceFlingerClient.h
rename to include/surfaceflinger/ISurfaceComposerClient.h
index c96432f..b2a4766 100644
--- a/include/surfaceflinger/ISurfaceFlingerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SF_ISURFACE_FLINGER_CLIENT_H
-#define ANDROID_SF_ISURFACE_FLINGER_CLIENT_H
+#ifndef ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H
+#define ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -26,7 +26,7 @@
 #include <binder/IInterface.h>
 
 #include <ui/PixelFormat.h>
-  
+
 #include <surfaceflinger/ISurface.h>
 
 namespace android {
@@ -42,10 +42,10 @@
 
 class layer_state_t;
 
-class ISurfaceFlingerClient : public IInterface
+class ISurfaceComposerClient : public IInterface
 {
-public: 
-    DECLARE_META_INTERFACE(SurfaceFlingerClient);
+public:
+    DECLARE_META_INTERFACE(SurfaceComposerClient);
 
     struct surface_data_t {
         int32_t             token;
@@ -56,21 +56,21 @@
         status_t readFromParcel(const Parcel& parcel);
         status_t writeToParcel(Parcel* parcel) const;
     };
-    
+
     virtual sp<IMemoryHeap> getControlBlock() const = 0;
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual sp<ISurface> createSurface( surface_data_t* data,
-                                        int pid, 
+                                        int pid,
                                         const String8& name,
                                         DisplayID display,
                                         uint32_t w,
                                         uint32_t h,
                                         PixelFormat format,
                                         uint32_t flags) = 0;
-                                    
+
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
@@ -84,7 +84,7 @@
 
 // ----------------------------------------------------------------------------
 
-class BnSurfaceFlingerClient : public BnInterface<ISurfaceFlingerClient>
+class BnSurfaceComposerClient : public BnInterface<ISurfaceComposerClient>
 {
 public:
     virtual status_t    onTransact( uint32_t code,
@@ -97,4 +97,4 @@
 
 }; // namespace android
 
-#endif // ANDROID_SF_ISURFACE_FLINGER_CLIENT_H
+#endif // ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 33269cb..2957970 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -28,7 +28,7 @@
 #include <ui/egl/android_natives.h>
 
 #include <surfaceflinger/ISurface.h>
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 
 #define ANDROID_VIEW_SURFACE_JNI_ID    "mNativeSurface"
 
@@ -108,7 +108,7 @@
     SurfaceControl(
             const sp<SurfaceComposerClient>& client,
             const sp<ISurface>& surface,
-            const ISurfaceFlingerClient::surface_data_t& data,
+            const ISurfaceComposerClient::surface_data_t& data,
             uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
 
     ~SurfaceControl();
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 102aebc6..8e28a81 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -149,7 +149,7 @@
                 // these don't need to be protected because they never change
                 // after assignment
                 status_t                    mStatus;
-                sp<ISurfaceFlingerClient>   mClient;
+                sp<ISurfaceComposerClient>  mClient;
 };
 
 // ---------------------------------------------------------------------------
@@ -161,7 +161,7 @@
     SharedClient*               mControl;
     sp<IMemoryHeap>             mControlMemory;
     sp<IBinder>                 mConnection;
-    sp<ISurfaceComposer>        mSignalServer;
+    sp<ISurfaceComposer>        mComposerService;
     void init(const sp<IBinder>& conn);
 public:
     explicit SurfaceClient(const sp<IBinder>& conn);
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index bc7626a8..3b975b4 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -54,11 +54,13 @@
  * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
  * and avoid to have a copy of them in each compilation units Singleton<TYPE>
  * is used.
+ * NOTE: we use a version of Mutex ctor that takes a parameter, because
+ * for some unknown reason using the default ctor doesn't emit the variable!
  */
 
-#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)             \
-    template class Singleton< TYPE >;                       \
-    template< class TYPE > Mutex Singleton< TYPE >::sLock;  \
+#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)                 \
+    template class Singleton< TYPE >;                           \
+    template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE);  \
     template<> TYPE* Singleton< TYPE >::sInstance(0);
 
 
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 870c0b8..22ecc54 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -87,7 +87,8 @@
     libutils \
     libbinder \
     libmedia \
-    libhardware_legacy
+    libhardware_legacy \
+    libeffects
 
 ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
   LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 3b38d83..1860793 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -37,7 +37,7 @@
 #include <media/AudioRecord.h>
 
 #include <private/media/AudioTrackShared.h>
-
+#include <private/media/AudioEffectShared.h>
 #include <hardware_legacy/AudioHardwareInterface.h>
 
 #include "AudioMixer.h"
@@ -51,6 +51,8 @@
 #include "lifevibes.h"
 #endif
 
+#include <media/EffectFactoryApi.h>
+
 // ----------------------------------------------------------------------------
 // the sim build doesn't have gettid
 
@@ -67,6 +69,7 @@
 
 //static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 static const float MAX_GAIN = 4096.0f;
+static const float MAX_GAIN_INT = 0x1000;
 
 // retry counts for buffer fill timeout
 // 50 * ~20msecs = 1 second
@@ -123,7 +126,7 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
+        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
 
@@ -282,6 +285,7 @@
         uint32_t flags,
         const sp<IMemory>& sharedBuffer,
         int output,
+        int *sessionId,
         status_t *status)
 {
     sp<PlaybackThread::Track> track;
@@ -289,6 +293,7 @@
     sp<Client> client;
     wp<Client> wclient;
     status_t lStatus;
+    int lSessionId;
 
     if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
@@ -313,8 +318,23 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
+
+        // If no audio session id is provided, create one here
+        // TODO: enforce same stream type for all tracks in same audio session?
+        // TODO: prevent same audio session on different output threads
+        LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
+        if (sessionId != NULL && *sessionId != 0) {
+            lSessionId = *sessionId;
+        } else {
+            lSessionId = nextUniqueId();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
+        }
+        LOGV("createTrack() lSessionId: %d", lSessionId);
+
         track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer, &lStatus);
+                channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
     }
     if (lStatus == NO_ERROR) {
         trackHandle = new TrackHandle(track);
@@ -940,10 +960,11 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   ThreadBase(audioFlinger, id),
         mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
-        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
+        mDevice(device)
 {
     readOutputParameters();
 
@@ -965,6 +986,7 @@
 {
     dumpInternals(fd, args);
     dumpTracks(fd, args);
+    dumpEffectChains(fd, args);
     return NO_ERROR;
 }
 
@@ -976,7 +998,7 @@
 
     snprintf(buffer, SIZE, "Output thread %p tracks\n", this);
     result.append(buffer);
-    result.append("   Name Clien Typ Fmt Chn Buf  S M F SRate  LeftV RighV Serv     User\n");
+    result.append("   Name  Clien Typ Fmt Chn Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");
     for (size_t i = 0; i < mTracks.size(); ++i) {
         sp<Track> track = mTracks[i];
         if (track != 0) {
@@ -987,7 +1009,7 @@
 
     snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);
     result.append(buffer);
-    result.append("   Name Clien Typ Fmt Chn Buf  S M F SRate  LeftV RighV Serv     User\n");
+    result.append("   Name  Clien Typ Fmt Chn Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");
     for (size_t i = 0; i < mActiveTracks.size(); ++i) {
         wp<Track> wTrack = mActiveTracks[i];
         if (wTrack != 0) {
@@ -1002,6 +1024,24 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::PlaybackThread::dumpEffectChains(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size());
+    write(fd, buffer, strlen(buffer));
+
+    for (size_t i = 0; i < mEffectChains.size(); ++i) {
+        sp<EffectChain> chain = mEffectChains[i];
+        if (chain != 0) {
+            chain->dump(fd, args);
+        }
+    }
+    return NO_ERROR;
+}
+
 status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -1020,6 +1060,8 @@
     result.append(buffer);
     snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended);
     result.append(buffer);
+    snprintf(buffer, SIZE, "mix buffer : %p\n", mMixBuffer);
+    result.append(buffer);
     write(fd, result.string(), result.size());
 
     dumpBase(fd, args);
@@ -1057,6 +1099,7 @@
         int channelCount,
         int frameCount,
         const sp<IMemory>& sharedBuffer,
+        int sessionId,
         status_t *status)
 {
     sp<Track> track;
@@ -1087,12 +1130,18 @@
     { // scope for mLock
         Mutex::Autolock _l(mLock);
         track = new Track(this, client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer);
+                channelCount, frameCount, sharedBuffer, sessionId);
         if (track->getCblk() == NULL || track->name() < 0) {
             lStatus = NO_MEMORY;
             goto Exit;
         }
         mTracks.add(track);
+
+        sp<EffectChain> chain = getEffectChain_l(sessionId);
+        if (chain != 0) {
+            LOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
+            track->setMainBuffer(chain->inBuffer());
+        }
     }
     lStatus = NO_ERROR;
 
@@ -1209,6 +1258,14 @@
         track->mFillingUpStatus = Track::FS_FILLING;
         track->mResetDone = false;
         mActiveTracks.add(track);
+        if (track->mainBuffer() != mMixBuffer) {
+            sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+            if (chain != 0) {
+                LOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId());
+                chain->startTrack();
+            }
+        }
+
         status = NO_ERROR;
     }
 
@@ -1271,9 +1328,11 @@
 
     // FIXME - Current mixer implementation only supports stereo output: Always
     // Allocate a stereo buffer even if HW output is mono.
-    if (mMixBuffer != NULL) delete mMixBuffer;
+    if (mMixBuffer != NULL) delete[] mMixBuffer;
     mMixBuffer = new int16_t[mFrameCount * 2];
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+
+    //TODO handle effects reconfig
 }
 
 status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
@@ -1289,10 +1348,47 @@
     return mOutput->getRenderPosition(dspFrames);
 }
 
+bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    if (getEffectChain_l(sessionId) != 0) {
+        return true;
+    }
+
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<Track> track = mTracks[i];
+        if (sessionId == track->sessionId()) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    return getEffectChain_l(sessionId);
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId)
+{
+    sp<EffectChain> chain;
+
+    size_t size = mEffectChains.size();
+    for (size_t i = 0; i < size; i++) {
+        if (mEffectChains[i]->sessionId() == sessionId) {
+            chain = mEffectChains[i];
+            break;
+        }
+    }
+    return chain;
+}
+
 // ----------------------------------------------------------------------------
 
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
-    :   PlaybackThread(audioFlinger, output, id),
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
+    :   PlaybackThread(audioFlinger, output, id, device),
         mAudioMixer(0)
 {
     mType = PlaybackThread::MIXER;
@@ -1311,7 +1407,6 @@
 
 bool AudioFlinger::MixerThread::threadLoop()
 {
-    int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
     uint32_t mixerStatus = MIXER_IDLE;
     nsecs_t standbyTime = systemTime();
@@ -1324,6 +1419,7 @@
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
     uint32_t sleepTime = idleSleepTime;
+    Vector< sp<EffectChain> > effectChains;
 
     while (!exitPending())
     {
@@ -1382,13 +1478,20 @@
             }
 
             mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
+
+            // prevent any changes in effect chain list and in each effect chain
+            // during mixing and effect process as the audio buffers could be deleted
+            // or modified if an effect is created or deleted
+            effectChains = mEffectChains;
+            lockEffectChains_l();
        }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
-            mAudioMixer->process(curBuf);
+            mAudioMixer->process();
             sleepTime = 0;
             standbyTime = systemTime() + kStandbyTimeInNsecs;
+            //TODO: delay standby when effects have a tail
         } else {
             // If no tracks are ready, sleep once for the duration of an output
             // buffer size, then write 0s to the output
@@ -1400,10 +1503,11 @@
                 }
             } else if (mBytesWritten != 0 ||
                        (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
-                memset (curBuf, 0, mixBufferSize);
+                memset (mMixBuffer, 0, mixBufferSize);
                 sleepTime = 0;
                 LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
             }
+            // TODO add standby time extension fct of effect tail
         }
 
         if (mSuspended) {
@@ -1411,16 +1515,22 @@
         }
         // sleepTime == 0 means we must write to audio hardware
         if (sleepTime == 0) {
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            mBytesWritten += mixBufferSize;
+             for (size_t i = 0; i < effectChains.size(); i ++) {
+                 effectChains[i]->process_l();
+             }
+             // enable changes in effect chain
+             unlockEffectChains();
 #ifdef LVMX
             int audioOutputType = LifeVibes::getMixerType(mId, mType);
             if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-               LifeVibes::process(audioOutputType, curBuf, mixBufferSize);
+               LifeVibes::process(audioOutputType, mMixBuffer, mixBufferSize);
             }
 #endif
-            int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            mBytesWritten += mixBufferSize;
+
+            int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
             if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
             mNumWrites++;
             mInWrite = false;
@@ -1439,6 +1549,8 @@
             }
             mStandby = false;
         } else {
+            // enable changes in effect chain
+            unlockEffectChains();
             usleep(sleepTime);
         }
 
@@ -1446,6 +1558,10 @@
         // since we can't guarantee the destructors won't acquire that
         // same lock.
         tracksToRemove.clear();
+
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+        effectChains.clear();
     }
 
     if (!mStandby) {
@@ -1463,6 +1579,8 @@
     uint32_t mixerStatus = MIXER_IDLE;
     // find out which tracks need to be processed
     size_t count = activeTracks.size();
+    size_t mixedTracks = 0;
+    size_t tracksWithEffect = 0;
 
     float masterVolume = mMasterVolume;
     bool  masterMute = mMasterMute;
@@ -1485,6 +1603,14 @@
         LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute);
     }
 #endif
+    // Delegate master volume control to effect in output mix effect chain if needed
+    sp<EffectChain> chain = getEffectChain_l(0);
+    if (chain != 0) {
+        uint32_t v = (uint32_t)(masterVolume * (1 << 24));
+        chain->setVolume(&v, &v);
+        masterVolume = (float)((v + (1 << 23)) >> 24);
+        chain.clear();
+    }
 
     for (size_t i=0 ; i<count ; i++) {
         sp<Track> t = activeTracks[i].promote();
@@ -1501,11 +1627,42 @@
         {
             //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this);
 
+            mixedTracks++;
+
+            // track->mainBuffer() != mMixBuffer means there is an effect chain
+            // connected to the track
+            chain.clear();
+            if (track->mainBuffer() != mMixBuffer) {
+                chain = getEffectChain_l(track->sessionId());
+                // Delegate volume control to effect in track effect chain if needed
+                if (chain != 0) {
+                    tracksWithEffect++;
+                } else {
+                    LOGW("prepareTracks_l(): track %08x attached to effect but no chain found on session %d",
+                            track->name(), track->sessionId());
+                }
+            }
+
+
+            int param = AudioMixer::VOLUME;
+            if (track->mFillingUpStatus == Track::FS_FILLED) {
+                // no ramp for the first volume setting
+                track->mFillingUpStatus = Track::FS_ACTIVE;
+                if (track->mState == TrackBase::RESUMING) {
+                    track->mState = TrackBase::ACTIVE;
+                    param = AudioMixer::RAMP_VOLUME;
+                }
+            } else if (cblk->server != 0) {
+                // If the track is stopped before the first frame was mixed,
+                // do not apply ramp
+                param = AudioMixer::RAMP_VOLUME;
+            }
+
             // compute volume for this track
-            int16_t left, right;
+            int16_t left, right, aux;
             if (track->isMuted() || masterMute || track->isPausing() ||
                 mStreamTypes[track->type()].mute) {
-                left = right = 0;
+                left = right = aux = 0;
                 if (track->isPausing()) {
                     track->setPaused();
                 }
@@ -1524,31 +1681,28 @@
                 }
 #endif
                 float v = masterVolume * typeVolume;
-                float v_clamped = v * cblk->volume[0];
-                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                left = int16_t(v_clamped);
-                v_clamped = v * cblk->volume[1];
-                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                right = int16_t(v_clamped);
-            }
+                uint32_t vl = (uint32_t)(v * cblk->volume[0]) << 12;
+                uint32_t vr = (uint32_t)(v * cblk->volume[1]) << 12;
 
-            // XXX: these things DON'T need to be done each time
-            mAudioMixer->setBufferProvider(track);
-            mAudioMixer->enable(AudioMixer::MIXING);
-
-            int param = AudioMixer::VOLUME;
-            if (track->mFillingUpStatus == Track::FS_FILLED) {
-                // no ramp for the first volume setting
-                track->mFillingUpStatus = Track::FS_ACTIVE;
-                if (track->mState == TrackBase::RESUMING) {
-                    track->mState = TrackBase::ACTIVE;
-                    param = AudioMixer::RAMP_VOLUME;
+                // Delegate volume control to effect in track effect chain if needed
+                if (chain != 0 && chain->setVolume(&vl, &vr)) {
+                    // Do not ramp volume is volume is controlled by effect
+                    param = AudioMixer::VOLUME;
                 }
-            } else if (cblk->server != 0) {
-                // If the track is stopped before the first frame was mixed,
-                // do not apply ramp
-                param = AudioMixer::RAMP_VOLUME;
+
+                // Convert volumes from 8.24 to 4.12 format
+                uint32_t v_clamped = (vl + (1 << 11)) >> 12;
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                left = int16_t(v_clamped);
+                v_clamped = (vr + (1 << 11)) >> 12;
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                right = int16_t(v_clamped);
+
+                v_clamped = (uint32_t)(v * cblk->sendLevel);
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                aux = int16_t(v_clamped);
             }
+
 #ifdef LVMX
             if ( tracksConnectedChanged || stateChanged )
             {
@@ -1556,18 +1710,30 @@
                  param = AudioMixer::VOLUME;
             }
 #endif
-            mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
-            mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+
+            // XXX: these things DON'T need to be done each time
+            mAudioMixer->setBufferProvider(track);
+            mAudioMixer->enable(AudioMixer::MIXING);
+
+            mAudioMixer->setParameter(param, AudioMixer::VOLUME0, (void *)left);
+            mAudioMixer->setParameter(param, AudioMixer::VOLUME1, (void *)right);
+            mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux);
             mAudioMixer->setParameter(
                 AudioMixer::TRACK,
-                AudioMixer::FORMAT, track->format());
+                AudioMixer::FORMAT, (void *)track->format());
             mAudioMixer->setParameter(
                 AudioMixer::TRACK,
-                AudioMixer::CHANNEL_COUNT, track->channelCount());
+                AudioMixer::CHANNEL_COUNT, (void *)track->channelCount());
             mAudioMixer->setParameter(
                 AudioMixer::RESAMPLE,
                 AudioMixer::SAMPLE_RATE,
-                int(cblk->sampleRate));
+                (void *)(cblk->sampleRate));
+            mAudioMixer->setParameter(
+                AudioMixer::TRACK,
+                AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
+            mAudioMixer->setParameter(
+                AudioMixer::TRACK,
+                AudioMixer::AUX_BUFFER, (void *)track->auxBuffer());
 
             // reset retry count
             track->mRetryCount = kMaxTrackRetries;
@@ -1581,7 +1747,6 @@
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
                 tracksToRemove->add(track);
-                mAudioMixer->disable(AudioMixer::MIXING);
             } else {
                 // No buffers for this track. Give it a few chances to
                 // fill a buffer, then remove it from active list.
@@ -1591,9 +1756,8 @@
                 } else if (mixerStatus != MIXER_TRACKS_READY) {
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
-
-                mAudioMixer->disable(AudioMixer::MIXING);
             }
+            mAudioMixer->disable(AudioMixer::MIXING);
         }
     }
 
@@ -1603,6 +1767,13 @@
         for (size_t i=0 ; i<count ; i++) {
             const sp<Track>& track = tracksToRemove->itemAt(i);
             mActiveTracks.remove(track);
+            if (track->mainBuffer() != mMixBuffer) {
+                chain = getEffectChain_l(track->sessionId());
+                if (chain != 0) {
+                    LOGV("stopping track on chain %p for session Id: %d", chain.get(), track->sessionId());
+                    chain->stopTrack();
+                }
+            }
             if (track->isTerminated()) {
                 mTracks.remove(track);
                 deleteTrackName_l(track->mName);
@@ -1610,6 +1781,13 @@
         }
     }
 
+    // mix buffer must be cleared if all tracks are connected to an
+    // effect chain as in this case the mixer will not write to
+    // mix buffer and track effects will accumulate into it
+    if (mixedTracks != 0 && mixedTracks == tracksWithEffect) {
+        memset(mMixBuffer, 0, mFrameCount * mChannelCount * sizeof(int16_t));
+    }
+
     return mixerStatus;
 }
 
@@ -1681,6 +1859,15 @@
                 reconfig = true;
             }
         }
+        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+            // forward device change to effects that have requested to be
+            // aware of attached audio device.
+            mDevice = (uint32_t)value;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setDevice(mDevice);
+            }
+        }
+
         if (status == NO_ERROR) {
             status = mOutput->setParameters(keyValuePair);
             if (!mStandby && status == INVALID_OPERATION) {
@@ -1740,9 +1927,8 @@
 }
 
 // ----------------------------------------------------------------------------
-AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
-    :   PlaybackThread(audioFlinger, output, id),
-    mLeftVolume (1.0), mRightVolume(1.0)
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
+    :   PlaybackThread(audioFlinger, output, id, device)
 {
     mType = PlaybackThread::DIRECT;
 }
@@ -1752,6 +1938,102 @@
 }
 
 
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+static inline
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smulbb %[out], %[in], %[v] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v)
+         : );
+    return out;
+#else
+    return in * int32_t(v);
+#endif
+}
+
+void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
+{
+    // Do not apply volume on compressed audio
+    if (!AudioSystem::isLinearPCM(mFormat)) {
+        return;
+    }
+
+    // convert to signed 16 bit before volume calculation
+    if (mFormat == AudioSystem::PCM_8_BIT) {
+        size_t count = mFrameCount * mChannelCount;
+        uint8_t *src = (uint8_t *)mMixBuffer + count-1;
+        int16_t *dst = mMixBuffer + count-1;
+        while(count--) {
+            *dst-- = (int16_t)(*src--^0x80) << 8;
+        }
+    }
+
+    size_t frameCount = mFrameCount;
+    int16_t *out = mMixBuffer;
+    if (ramp) {
+        if (mChannelCount == 1) {
+            int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16;
+            int32_t vlInc = d / (int32_t)frameCount;
+            int32_t vl = ((int32_t)mLeftVolShort << 16);
+            do {
+                out[0] = clamp16(mul(out[0], vl >> 16) >> 12);
+                out++;
+                vl += vlInc;
+            } while (--frameCount);
+
+        } else {
+            int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16;
+            int32_t vlInc = d / (int32_t)frameCount;
+            d = ((int32_t)rightVol - (int32_t)mRightVolShort) << 16;
+            int32_t vrInc = d / (int32_t)frameCount;
+            int32_t vl = ((int32_t)mLeftVolShort << 16);
+            int32_t vr = ((int32_t)mRightVolShort << 16);
+            do {
+                out[0] = clamp16(mul(out[0], vl >> 16) >> 12);
+                out[1] = clamp16(mul(out[1], vr >> 16) >> 12);
+                out += 2;
+                vl += vlInc;
+                vr += vrInc;
+            } while (--frameCount);
+        }
+    } else {
+        if (mChannelCount == 1) {
+            do {
+                out[0] = clamp16(mul(out[0], leftVol) >> 12);
+                out++;
+            } while (--frameCount);
+        } else {
+            do {
+                out[0] = clamp16(mul(out[0], leftVol) >> 12);
+                out[1] = clamp16(mul(out[1], rightVol) >> 12);
+                out += 2;
+            } while (--frameCount);
+        }
+    }
+
+    // convert back to unsigned 8 bit after volume calculation
+    if (mFormat == AudioSystem::PCM_8_BIT) {
+        size_t count = mFrameCount * mChannelCount;
+        int16_t *src = mMixBuffer;
+        uint8_t *dst = (uint8_t *)mMixBuffer;
+        while(count--) {
+            *dst++ = (uint8_t)(((int32_t)*src++ + (1<<7)) >> 8)^0x80;
+        }
+    }
+
+    mLeftVolShort = leftVol;
+    mRightVolShort = rightVol;
+}
+
 bool AudioFlinger::DirectOutputThread::threadLoop()
 {
     uint32_t mixerStatus = MIXER_IDLE;
@@ -1770,6 +2052,11 @@
 
     while (!exitPending())
     {
+        bool rampVolume;
+        uint16_t leftVol;
+        uint16_t rightVol;
+        Vector< sp<EffectChain> > effectChains;
+
         processConfigEvents();
 
         mixerStatus = MIXER_IDLE;
@@ -1821,6 +2108,8 @@
                 }
             }
 
+            effectChains = mEffectChains;
+
             // find out which tracks need to be processed
             if (mActiveTracks.size() != 0) {
                 sp<Track> t = mActiveTracks[0].promote();
@@ -1836,6 +2125,19 @@
                 {
                     //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
 
+                    if (track->mFillingUpStatus == Track::FS_FILLED) {
+                        track->mFillingUpStatus = Track::FS_ACTIVE;
+                        mLeftVolFloat = mRightVolFloat = 0;
+                        mLeftVolShort = mRightVolShort = 0;
+                        if (track->mState == TrackBase::RESUMING) {
+                            track->mState = TrackBase::ACTIVE;
+                            rampVolume = true;
+                        }
+                    } else if (cblk->server != 0) {
+                        // If the track is stopped before the first frame was mixed,
+                        // do not apply ramp
+                        rampVolume = true;
+                    }
                     // compute volume for this track
                     float left, right;
                     if (track->isMuted() || mMasterMute || track->isPausing() ||
@@ -1855,17 +2157,42 @@
                         right = v_clamped/MAX_GAIN;
                     }
 
-                    if (left != mLeftVolume || right != mRightVolume) {
-                        mOutput->setVolume(left, right);
-                        left = mLeftVolume;
-                        right = mRightVolume;
-                    }
+                    if (left != mLeftVolFloat || right != mRightVolFloat) {
+                        mLeftVolFloat = left;
+                        mRightVolFloat = right;
 
-                    if (track->mFillingUpStatus == Track::FS_FILLED) {
-                        track->mFillingUpStatus = Track::FS_ACTIVE;
-                        if (track->mState == TrackBase::RESUMING) {
-                            track->mState = TrackBase::ACTIVE;
+                        // If audio HAL implements volume control,
+                        // force software volume to nominal value
+                        if (mOutput->setVolume(left, right) == NO_ERROR) {
+                            left = 1.0f;
+                            right = 1.0f;
                         }
+
+                        // Convert volumes from float to 8.24
+                        uint32_t vl = (uint32_t)(left * (1 << 24));
+                        uint32_t vr = (uint32_t)(right * (1 << 24));
+
+                        // Delegate volume control to effect in track effect chain if needed
+                        // only one effect chain can be present on DirectOutputThread, so if
+                        // there is one, the track is connected to it
+                        if (!effectChains.isEmpty()) {
+                            // Do not ramp volume is volume is controlled by effect
+                            if(effectChains[0]->setVolume(&vl, &vr)) {
+                                rampVolume = false;
+                            }
+                        }
+
+                        // Convert volumes from 8.24 to 4.12 format
+                        uint32_t v_clamped = (vl + (1 << 11)) >> 12;
+                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                        leftVol = (uint16_t)v_clamped;
+                        v_clamped = (vr + (1 << 11)) >> 12;
+                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                        rightVol = (uint16_t)v_clamped;
+                    } else {
+                        leftVol = mLeftVolShort;
+                        rightVol = mRightVolShort;
+                        rampVolume = false;
                     }
 
                     // reset retry count
@@ -1897,11 +2224,17 @@
             // remove all the tracks that need to be...
             if (UNLIKELY(trackToRemove != 0)) {
                 mActiveTracks.remove(trackToRemove);
+                if (!effectChains.isEmpty()) {
+                    LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId());
+                    effectChains[0]->stopTrack();
+                }
                 if (trackToRemove->isTerminated()) {
                     mTracks.remove(trackToRemove);
                     deleteTrackName_l(trackToRemove->mName);
                 }
             }
+
+            lockEffectChains_l();
        }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
@@ -1909,7 +2242,7 @@
             size_t frameCount = mFrameCount;
             curBuf = (int8_t *)mMixBuffer;
             // output audio to hardware
-            while(frameCount) {
+            while (frameCount) {
                 buffer.frameCount = frameCount;
                 activeTrack->getNextBuffer(&buffer);
                 if (UNLIKELY(buffer.raw == 0)) {
@@ -1941,6 +2274,14 @@
         }
         // sleepTime == 0 means we must write to audio hardware
         if (sleepTime == 0) {
+            if (mixerStatus == MIXER_TRACKS_READY) {
+                applyVolume(leftVol, rightVol, rampVolume);
+            }
+            for (size_t i = 0; i < effectChains.size(); i ++) {
+                effectChains[i]->process_l();
+            }
+            unlockEffectChains();
+
             mLastWriteTime = systemTime();
             mInWrite = true;
             mBytesWritten += mixBufferSize;
@@ -1950,6 +2291,7 @@
             mInWrite = false;
             mStandby = false;
         } else {
+            unlockEffectChains();
             usleep(sleepTime);
         }
 
@@ -1958,6 +2300,10 @@
         // same lock.
         trackToRemove.clear();
         activeTrack.clear();
+
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+        effectChains.clear();
     }
 
     if (!mStandby) {
@@ -2048,7 +2394,7 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id), mWaitTimeMs(UINT_MAX)
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)
 {
     mType = PlaybackThread::DUPLICATING;
     addOutputTrack(mainThread);
@@ -2064,7 +2410,6 @@
 
 bool AudioFlinger::DuplicatingThread::threadLoop()
 {
-    int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
     uint32_t mixerStatus = MIXER_IDLE;
     nsecs_t standbyTime = systemTime();
@@ -2074,6 +2419,7 @@
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
     uint32_t sleepTime = idleSleepTime;
+    Vector< sp<EffectChain> > effectChains;
 
     while (!exitPending())
     {
@@ -2134,14 +2480,20 @@
             }
 
             mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
+
+            // prevent any changes in effect chain list and in each effect chain
+            // during mixing and effect process as the audio buffers could be deleted
+            // or modified if an effect is created or deleted
+            effectChains = mEffectChains;
+            lockEffectChains_l();
         }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
             if (outputsReady(outputTracks)) {
-                mAudioMixer->process(curBuf);
+                mAudioMixer->process();
             } else {
-                memset(curBuf, 0, mixBufferSize);
+                memset(mMixBuffer, 0, mixBufferSize);
             }
             sleepTime = 0;
             writeFrames = mFrameCount;
@@ -2158,6 +2510,7 @@
                     if (outputTracks[i]->isActive()) {
                         sleepTime = 0;
                         writeFrames = 0;
+                        memset(mMixBuffer, 0, mixBufferSize);
                         break;
                     }
                 }
@@ -2169,13 +2522,21 @@
         }
         // sleepTime == 0 means we must write to audio hardware
         if (sleepTime == 0) {
+            for (size_t i = 0; i < effectChains.size(); i ++) {
+                effectChains[i]->process_l();
+            }
+            // enable changes in effect chain
+            unlockEffectChains();
+
             standbyTime = systemTime() + kStandbyTimeInNsecs;
             for (size_t i = 0; i < outputTracks.size(); i++) {
-                outputTracks[i]->write(curBuf, writeFrames);
+                outputTracks[i]->write(mMixBuffer, writeFrames);
             }
             mStandby = false;
             mBytesWritten += mixBufferSize;
         } else {
+            // enable changes in effect chain
+            unlockEffectChains();
             usleep(sleepTime);
         }
 
@@ -2184,6 +2545,10 @@
         // same lock.
         tracksToRemove.clear();
         outputTracks.clear();
+
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+        effectChains.clear();
     }
 
     return false;
@@ -2268,7 +2633,8 @@
             int channelCount,
             int frameCount,
             uint32_t flags,
-            const sp<IMemory>& sharedBuffer)
+            const sp<IMemory>& sharedBuffer,
+            int sessionId)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -2277,7 +2643,8 @@
         mState(IDLE),
         mClientTid(-1),
         mFormat(format),
-        mFlags(flags & ~SYSTEM_FLAGS_MASK)
+        mFlags(flags & ~SYSTEM_FLAGS_MASK),
+        mSessionId(sessionId)
 {
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
@@ -2420,15 +2787,17 @@
             int format,
             int channelCount,
             int frameCount,
-            const sp<IMemory>& sharedBuffer)
-    :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
-    mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
+            const sp<IMemory>& sharedBuffer,
+            int sessionId)
+    :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId),
+    mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0)
 {
     if (mCblk != NULL) {
         sp<ThreadBase> baseThread = thread.promote();
         if (baseThread != 0) {
             PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
             mName = playbackThread->getTrackName_l();
+            mMainBuffer = playbackThread->mixBuffer();
         }
         LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
         if (mName < 0) {
@@ -2482,12 +2851,13 @@
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
 {
-    snprintf(buffer, size, "  %5d %5d %3u %3u %3u %04u %1d %1d %1d %5u %5u %5u  %08x %08x\n",
+    snprintf(buffer, size, "   %05d %05d %03u %03u %03u %05u   %04u %1d %1d %1d %05u %05u %05u  0x%08x 0x%08x 0x%08x 0x%08x\n",
             mName - AudioMixer::TRACK0,
             (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
             mCblk->channelCount,
+            mSessionId,
             mFrameCount,
             mState,
             mMute,
@@ -2496,7 +2866,9 @@
             mCblk->volume[0],
             mCblk->volume[1],
             mCblk->server,
-            mCblk->user);
+            mCblk->user,
+            (int)mMainBuffer,
+            (int)mAuxBuffer);
 }
 
 status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
@@ -2679,6 +3051,23 @@
     mVolume[1] = right;
 }
 
+status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
+{
+    status_t status = DEAD_OBJECT;
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+       PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+       status = playbackThread->attachAuxEffect(this, EffectId);
+    }
+    return status;
+}
+
+void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer)
+{
+    mAuxEffectId = EffectId;
+    mAuxBuffer = buffer;
+}
+
 // ----------------------------------------------------------------------------
 
 // RecordTrack constructor must be called with AudioFlinger::mLock held
@@ -2689,9 +3078,10 @@
             int format,
             int channelCount,
             int frameCount,
-            uint32_t flags)
+            uint32_t flags,
+            int sessionId)
     :   TrackBase(thread, client, sampleRate, format,
-                  channelCount, frameCount, flags, 0),
+                  channelCount, frameCount, flags, 0, sessionId),
         mOverflow(false)
 {
     if (mCblk != NULL) {
@@ -2779,10 +3169,11 @@
 
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
 {
-    snprintf(buffer, size, "   %05d %03u %03u %04u %01d %05u  %08x %08x\n",
+    snprintf(buffer, size, "   %05d %03u %03u %05d   %04u %01d %05u  %08x %08x\n",
             (mClient == NULL) ? getpid() : mClient->pid(),
             mFormat,
             mCblk->channelCount,
+            mSessionId,
             mFrameCount,
             mState,
             mCblk->sampleRate,
@@ -2800,7 +3191,7 @@
             int format,
             int channelCount,
             int frameCount)
-    :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
+    :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL, 0),
     mActive(false), mSourceThread(sourceThread)
 {
 
@@ -3115,6 +3506,11 @@
     return mTrack->getCblk();
 }
 
+status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId)
+{
+    return mTrack->attachAuxEffect(EffectId);
+}
+
 status_t AudioFlinger::TrackHandle::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -3131,6 +3527,7 @@
         int channelCount,
         int frameCount,
         uint32_t flags,
+        int *sessionId,
         status_t *status)
 {
     sp<RecordThread::RecordTrack> recordTrack;
@@ -3140,6 +3537,7 @@
     status_t lStatus;
     RecordThread *thread;
     size_t inFrameCount;
+    int lSessionId;
 
     // check calling permissions
     if (!recordingAllowed()) {
@@ -3164,9 +3562,18 @@
             mClients.add(pid, client);
         }
 
+        // If no audio session id is provided, create one here
+        if (sessionId != NULL && *sessionId != 0) {
+            lSessionId = *sessionId;
+        } else {
+            lSessionId = nextUniqueId();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
+        }
         // create new record track. The record track uses one track in mHardwareMixerThread by convention.
         recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
-                                                   format, channelCount, frameCount, flags);
+                                                   format, channelCount, frameCount, flags, lSessionId);
     }
     if (recordTrack->getCblk() == NULL) {
         // remove local strong reference to Client before deleting the RecordTrack so that the Client
@@ -3504,7 +3911,7 @@
 
     if (mActiveTrack != 0) {
         result.append("Active Track:\n");
-        result.append("   Clien Fmt Chn Buf  S SRate  Serv     User\n");
+        result.append("   Clien Fmt Chn Session Buf  S SRate  Serv     User\n");
         mActiveTrack->dump(buffer, SIZE);
         result.append(buffer);
 
@@ -3753,14 +4160,15 @@
 
     mHardwareStatus = AUDIO_HW_IDLE;
     if (output != 0) {
+        int id = nextUniqueId();
         if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
             (format != AudioSystem::PCM_16_BIT) ||
             (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
-            thread = new DirectOutputThread(this, output, ++mNextThreadId);
-            LOGV("openOutput() created direct output: ID %d thread %p", mNextThreadId, thread);
+            thread = new DirectOutputThread(this, output, id, *pDevices);
+            LOGV("openOutput() created direct output: ID %d thread %p", id, thread);
         } else {
-            thread = new MixerThread(this, output, ++mNextThreadId);
-            LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread);
+            thread = new MixerThread(this, output, id, *pDevices);
+            LOGV("openOutput() created mixer output: ID %d thread %p", id, thread);
 
 #ifdef LVMX
             unsigned bitsPerSample =
@@ -3774,7 +4182,7 @@
 #endif
 
         }
-        mPlaybackThreads.add(mNextThreadId, thread);
+        mPlaybackThreads.add(id, thread);
 
         if (pSamplingRate) *pSamplingRate = samplingRate;
         if (pFormat) *pFormat = format;
@@ -3783,7 +4191,7 @@
 
         // notify client processes of the new output creation
         thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
-        return mNextThreadId;
+        return id;
     }
 
     return 0;
@@ -3800,13 +4208,13 @@
         return 0;
     }
 
-
-    DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);
+    int id = nextUniqueId();
+    DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
     thread->addOutputTrack(thread2);
-    mPlaybackThreads.add(mNextThreadId, thread);
+    mPlaybackThreads.add(id, thread);
     // notify client processes of the new output creation
     thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
-    return mNextThreadId;
+    return id;
 }
 
 status_t AudioFlinger::closeOutput(int output)
@@ -3925,10 +4333,11 @@
     }
 
     if (input != 0) {
+        int id = nextUniqueId();
          // Start record thread
-        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId);
-        mRecordThreads.add(mNextThreadId, thread);
-        LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
+        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id);
+        mRecordThreads.add(id, thread);
+        LOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate) *pSamplingRate = reqSamplingRate;
         if (pFormat) *pFormat = format;
         if (pChannels) *pChannels = reqChannels;
@@ -3937,7 +4346,7 @@
 
         // notify client processes of the new input creation
         thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
-        return mNextThreadId;
+        return id;
     }
 
     return 0;
@@ -3991,6 +4400,12 @@
     return NO_ERROR;
 }
 
+
+int AudioFlinger::newAudioSessionId()
+{
+    return nextUniqueId();
+}
+
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
 {
@@ -4023,6 +4438,1475 @@
     return thread;
 }
 
+int AudioFlinger::nextUniqueId()
+{
+    return android_atomic_inc(&mNextUniqueId);
+}
+
+// ----------------------------------------------------------------------------
+//  Effect management
+// ----------------------------------------------------------------------------
+
+
+status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectLoadLibrary(libPath, handle);
+}
+
+status_t AudioFlinger::unloadEffectLibrary(int handle)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectUnloadLibrary(handle);
+}
+
+status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectQueryNumberEffects(numEffects);
+}
+
+status_t AudioFlinger::queryNextEffect(effect_descriptor_t *descriptor)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectQueryNext(descriptor);
+}
+
+status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectGetDescriptor(pUuid, descriptor);
+}
+
+sp<IEffect> AudioFlinger::createEffect(pid_t pid,
+        effect_descriptor_t *pDesc,
+        const sp<IEffectClient>& effectClient,
+        int32_t priority,
+        int output,
+        int sessionId,
+        status_t *status,
+        int *id,
+        int *enabled)
+{
+    status_t lStatus = NO_ERROR;
+    sp<EffectHandle> handle;
+    effect_interface_t itfe;
+    effect_descriptor_t desc;
+    sp<Client> client;
+    wp<Client> wclient;
+
+    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output);
+
+    if (pDesc == NULL) {
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (!EffectIsNullUuid(&pDesc->uuid)) {
+            // if uuid is specified, request effect descriptor
+            lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);
+            if (lStatus < 0) {
+                LOGW("createEffect() error %d from EffectGetDescriptor", lStatus);
+                goto Exit;
+            }
+        } else {
+            // if uuid is not specified, look for an available implementation
+            // of the required type in effect factory
+            if (EffectIsNullUuid(&pDesc->type)) {
+                LOGW("createEffect() no effect type");
+                lStatus = BAD_VALUE;
+                goto Exit;
+            }
+            uint32_t numEffects = 0;
+            effect_descriptor_t d;
+            bool found = false;
+
+            lStatus = EffectQueryNumberEffects(&numEffects);
+            if (lStatus < 0) {
+                LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
+                goto Exit;
+            }
+            for (; numEffects > 0; numEffects--) {
+                lStatus = EffectQueryNext(&desc);
+                if (lStatus < 0) {
+                    LOGW("createEffect() error %d from EffectQueryNext", lStatus);
+                    continue;
+                }
+                if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
+                    // If matching type found save effect descriptor. If the session is
+                    // 0 and the effect is not auxiliary, continue enumeration in case
+                    // an auxiliary version of this effect type is available
+                    found = true;
+                    memcpy(&d, &desc, sizeof(effect_descriptor_t));
+                    if (sessionId != 0 ||
+                            (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                        break;
+                    }
+                }
+            }
+            if (!found) {
+                lStatus = BAD_VALUE;
+                LOGW("createEffect() effect not found");
+                goto Exit;
+            }
+            // For same effect type, chose auxiliary version over insert version if
+            // connect to output mix (Compliance to OpenSL ES)
+            if (sessionId == 0 &&
+                    (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
+                memcpy(&desc, &d, sizeof(effect_descriptor_t));
+            }
+        }
+
+        // Do not allow auxiliary effects on a session different from 0 (output mix)
+        if (sessionId != 0 &&
+             (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            lStatus = INVALID_OPERATION;
+            goto Exit;
+        }
+
+        // return effect descriptor
+        memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
+
+        // If output is not specified try to find a matching audio session ID in one of the
+        // output threads.
+        // TODO: allow attachment of effect to inputs
+        if (output == 0) {
+            if (sessionId == 0) {
+                // default to first output
+                // TODO: define criteria to choose output when not specified. Or
+                // receive output from audio policy manager
+                if (mPlaybackThreads.size() != 0) {
+                    output = mPlaybackThreads.keyAt(0);
+                }
+            } else {
+                 // look for the thread where the specified audio session is present
+                for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+                    if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId)) {
+                        output = mPlaybackThreads.keyAt(i);
+                        break;
+                    }
+                }
+            }
+        }
+        PlaybackThread *thread = checkPlaybackThread_l(output);
+        if (thread == NULL) {
+            LOGE("unknown output thread");
+            lStatus = BAD_VALUE;
+            goto Exit;
+        }
+
+        wclient = mClients.valueFor(pid);
+
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+
+        // create effect on selected output trhead
+        handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus);
+        if (handle != 0 && id != NULL) {
+            *id = handle->id();
+        }
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return handle;
+}
+
+// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
+        const sp<AudioFlinger::Client>& client,
+        const sp<IEffectClient>& effectClient,
+        int32_t priority,
+        int sessionId,
+        effect_descriptor_t *desc,
+        int *enabled,
+        status_t *status
+        )
+{
+    sp<EffectModule> effect;
+    sp<EffectHandle> handle;
+    status_t lStatus;
+    sp<Track> track;
+    sp<EffectChain> chain;
+    bool effectCreated = false;
+
+    if (mOutput == 0) {
+        LOGW("createEffect_l() Audio driver not initialized.");
+        lStatus = NO_INIT;
+        goto Exit;
+    }
+
+    // Do not allow auxiliary effect on session other than 0
+    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&
+        sessionId != 0) {
+        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    // Do not allow effects with session ID 0 on direct output or duplicating threads
+    // TODO: add rule for hw accelerated effects on direct outputs with non PCM format
+    if (sessionId == 0 && mType != MIXER) {
+        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId);
+
+    { // scope for mLock
+        Mutex::Autolock _l(mLock);
+
+        // check for existing effect chain with the requested audio session
+        chain = getEffectChain_l(sessionId);
+        if (chain == 0) {
+            // create a new chain for this session
+            LOGV("createEffect_l() new effect chain for session %d", sessionId);
+            chain = new EffectChain(this, sessionId);
+            addEffectChain_l(chain);
+        } else {
+            effect = chain->getEffectFromDesc(desc);
+        }
+
+        LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
+
+        if (effect == 0) {
+            // create a new effect module if none present in the chain
+            effectCreated = true;
+            effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId);
+            lStatus = effect->status();
+            if (lStatus != NO_ERROR) {
+                goto Exit;
+            }
+            //TODO: handle CPU load and memory usage here
+            lStatus = chain->addEffect(effect);
+            if (lStatus != NO_ERROR) {
+                goto Exit;
+            }
+
+            effect->setDevice(mDevice);
+        }
+        // create effect handle and connect it to effect module
+        handle = new EffectHandle(effect, client, effectClient, priority);
+        lStatus = effect->addHandle(handle);
+        if (enabled) {
+            *enabled = (int)effect->isEnabled();
+        }
+    }
+
+Exit:
+    if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+        if (chain != 0 && effectCreated) {
+            if (chain->removeEffect(effect) == 0) {
+                removeEffectChain_l(chain);
+            }
+        }
+        handle.clear();
+    }
+
+    if(status) {
+        *status = lStatus;
+    }
+    return handle;
+}
+
+status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
+{
+    int session = chain->sessionId();
+    int16_t *buffer = mMixBuffer;
+
+    LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
+    if (session == 0) {
+        chain->setInBuffer(buffer, false);
+        chain->setOutBuffer(buffer);
+        // Effect chain for session 0 is inserted at end of effect chains list
+        // to be processed last as it contains output mix effects to apply after
+        // all track specific effects
+        mEffectChains.add(chain);
+    } else {
+        bool ownsBuffer = false;
+        // Only one effect chain can be present in direct output thread and it uses
+        // the mix buffer as input
+        if (mType != DIRECT) {
+            size_t numSamples = mFrameCount * mChannelCount;
+            buffer = new int16_t[numSamples];
+            memset(buffer, 0, numSamples * sizeof(int16_t));
+            LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);
+            ownsBuffer = true;
+        }
+        chain->setInBuffer(buffer, ownsBuffer);
+        chain->setOutBuffer(mMixBuffer);
+        // Effect chain for session other than 0 is inserted at beginning of effect
+        // chains list to be processed before output mix effects. Relative order between
+        // sessions other than 0 is not important
+        mEffectChains.insertAt(chain, 0);
+    }
+
+    // Attach all tracks with same session ID to this chain.
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<Track> track = mTracks[i];
+        if (session == track->sessionId()) {
+            LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
+            track->setMainBuffer(buffer);
+        }
+    }
+
+    // indicate all active tracks in the chain
+    for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+        sp<Track> track = mActiveTracks[i].promote();
+        if (track == 0) continue;
+        if (session == track->sessionId()) {
+            LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
+            chain->startTrack();
+        }
+    }
+
+    return NO_ERROR;
+}
+
+size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& chain)
+{
+    int session = chain->sessionId();
+
+    LOGV("removeEffectChain_l() %p from thread %p for session %d", chain.get(), this, session);
+
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        if (chain == mEffectChains[i]) {
+            mEffectChains.removeAt(i);
+            // detach all tracks with same session ID from this chain
+            for (size_t i = 0; i < mTracks.size(); ++i) {
+                sp<Track> track = mTracks[i];
+                if (session == track->sessionId()) {
+                    track->setMainBuffer(mMixBuffer);
+                }
+            }
+        }
+    }
+    return mEffectChains.size();
+}
+
+void AudioFlinger::PlaybackThread::lockEffectChains_l()
+{
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->lock();
+    }
+}
+
+void AudioFlinger::PlaybackThread::unlockEffectChains()
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->unlock();
+    }
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)
+{
+    sp<EffectModule> effect;
+
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    if (chain != 0) {
+        effect = chain->getEffectFromId(effectId);
+    }
+    return effect;
+}
+
+status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+{
+    Mutex::Autolock _l(mLock);
+    return attachAuxEffect_l(track, EffectId);
+}
+
+status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+{
+    status_t status = NO_ERROR;
+
+    if (EffectId == 0) {
+        track->setAuxBuffer(0, NULL);
+    } else {
+        // Auxiliary effects are always in audio session 0
+        sp<EffectModule> effect = getEffect_l(0, EffectId);
+        if (effect != 0) {
+            if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer());
+            } else {
+                status = INVALID_OPERATION;
+            }
+        } else {
+            status = BAD_VALUE;
+        }
+    }
+    return status;
+}
+
+void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId)
+{
+     for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<Track> track = mTracks[i];
+        if (track->auxEffectId() == effectId) {
+            attachAuxEffect_l(track, 0);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+//  EffectModule implementation
+// ----------------------------------------------------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectModule"
+
+AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,
+                                        const wp<AudioFlinger::EffectChain>& chain,
+                                        effect_descriptor_t *desc,
+                                        int id,
+                                        int sessionId)
+    : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),
+      mStatus(NO_INIT), mState(IDLE)
+{
+    LOGV("Constructor %p", this);
+    int lStatus;
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return;
+    }
+    PlaybackThread *p = (PlaybackThread *)thread.get();
+
+    memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
+
+    // create effect engine from effect factory
+    mStatus = EffectCreate(&desc->uuid, &mEffectInterface);
+    if (mStatus != NO_ERROR) {
+        return;
+    }
+    lStatus = init();
+    if (lStatus < 0) {
+        mStatus = lStatus;
+        goto Error;
+    }
+
+    LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
+    return;
+Error:
+    EffectRelease(mEffectInterface);
+    mEffectInterface = NULL;
+    LOGV("Constructor Error %d", mStatus);
+}
+
+AudioFlinger::EffectModule::~EffectModule()
+{
+    LOGV("Destructor %p", this);
+    if (mEffectInterface != NULL) {
+        // release effect engine
+        EffectRelease(mEffectInterface);
+    }
+}
+
+status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle)
+{
+    status_t status;
+
+    Mutex::Autolock _l(mLock);
+    // First handle in mHandles has highest priority and controls the effect module
+    int priority = handle->priority();
+    size_t size = mHandles.size();
+    sp<EffectHandle> h;
+    size_t i;
+    for (i = 0; i < size; i++) {
+        h = mHandles[i].promote();
+        if (h == 0) continue;
+        if (h->priority() <= priority) break;
+    }
+    // if inserted in first place, move effect control from previous owner to this handle
+    if (i == 0) {
+        if (h != 0) {
+            h->setControl(false, true);
+        }
+        handle->setControl(true, false);
+        status = NO_ERROR;
+    } else {
+        status = ALREADY_EXISTS;
+    }
+    mHandles.insertAt(handle, i);
+    return status;
+}
+
+size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
+{
+    Mutex::Autolock _l(mLock);
+    size_t size = mHandles.size();
+    size_t i;
+    for (i = 0; i < size; i++) {
+        if (mHandles[i] == handle) break;
+    }
+    if (i == size) {
+        return size;
+    }
+    mHandles.removeAt(i);
+    size = mHandles.size();
+    // if removed from first place, move effect control from this handle to next in line
+    if (i == 0 && size != 0) {
+        sp<EffectHandle> h = mHandles[0].promote();
+        if (h != 0) {
+            h->setControl(true, true);
+        }
+    }
+
+    return size;
+}
+
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
+{
+    // keep a strong reference on this EffectModule to avoid calling the
+    // destructor before we exit
+    sp<EffectModule> keep(this);
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        Mutex::Autolock _l(thread->mLock);
+        // delete the effect module if removing last handle on it
+        if (removeHandle(handle) == 0) {
+            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+            if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                playbackThread->detachAuxEffect_l(mId);
+            }
+            sp<EffectChain> chain = mChain.promote();
+            if (chain != 0) {
+                // remove effect chain if remove last effect
+                if (chain->removeEffect(keep) == 0) {
+                    playbackThread->removeEffectChain_l(chain);
+                }
+            }
+        }
+    }
+}
+
+void AudioFlinger::EffectModule::process()
+{
+    Mutex::Autolock _l(mLock);
+
+    if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) {
+        return;
+    }
+
+    if (mState != IDLE) {
+        // do 32 bit to 16 bit conversion for auxiliary effect input buffer
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
+                                        mConfig.inputCfg.buffer.s32,
+                                        mConfig.inputCfg.buffer.frameCount);
+        }
+
+        // TODO: handle effects with buffer provider
+        if (mState != ACTIVE) {
+            uint32_t count = mConfig.inputCfg.buffer.frameCount;
+            int32_t amp = 32767L << 16;
+            int32_t step = amp / count;
+            int16_t *pIn = mConfig.inputCfg.buffer.s16;
+            int16_t *pOut = mConfig.outputCfg.buffer.s16;
+            int inChannels;
+            int outChannels;
+
+            if (mConfig.inputCfg.channels == CHANNEL_MONO) {
+                inChannels = 1;
+            } else {
+                inChannels = 2;
+            }
+            if (mConfig.outputCfg.channels == CHANNEL_MONO) {
+                outChannels = 1;
+            } else {
+                outChannels = 2;
+            }
+
+            switch (mState) {
+            case RESET:
+                reset();
+                // clear auxiliary effect input buffer for next accumulation
+                if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                    memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+                }
+                step = -step;
+                mState = STARTING;
+                break;
+            case STARTING:
+                start();
+                amp = 0;
+                pOut = mConfig.inputCfg.buffer.s16;
+                outChannels = inChannels;
+                mState = ACTIVE;
+                break;
+            case STOPPING:
+                step = -step;
+                pOut = mConfig.inputCfg.buffer.s16;
+                outChannels = inChannels;
+                mState = STOPPED;
+                break;
+            case STOPPED:
+                stop();
+                amp = 0;
+                mState = IDLE;
+                break;
+            }
+
+            // ramp volume down or up before activating or deactivating the effect
+            if (inChannels == 1) {
+                if (outChannels == 1) {
+                    while (count--) {
+                        *pOut++ = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
+                        amp += step;
+                    }
+                } else {
+                    while (count--) {
+                        int32_t smp = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
+                        *pOut++ = smp;
+                        *pOut++ = smp;
+                        amp += step;
+                    }
+                }
+            } else {
+                if (outChannels == 1) {
+                    while (count--) {
+                        int32_t smp = (((int32_t)*pIn * (amp >> 16)) >> 16) +
+                                      (((int32_t)*(pIn + 1) * (amp >> 16)) >> 16);
+                        pIn += 2;
+                        *pOut++ = (int16_t)smp;
+                        amp += step;
+                    }
+                } else {
+                    while (count--) {
+                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
+                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
+                         amp += step;
+                    }
+                }
+            }
+            if (mState == STARTING || mState == IDLE) {
+                return;
+            }
+        }
+
+        // do the actual processing in the effect engine
+        (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+
+        // clear auxiliary effect input buffer for next accumulation
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+        }
+    } else if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT &&
+                mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw){
+        // If an insert effect is idle and input buffer is different from output buffer, copy input to
+        // output
+        sp<EffectChain> chain = mChain.promote();
+        if (chain != 0 && chain->activeTracks() != 0) {
+            size_t size = mConfig.inputCfg.buffer.frameCount * sizeof(int16_t);
+            if (mConfig.inputCfg.channels == CHANNEL_STEREO) {
+                size *= 2;
+            }
+            memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw, size);
+        }
+    }
+}
+
+void AudioFlinger::EffectModule::reset()
+{
+    if (mEffectInterface == NULL) {
+        return;
+    }
+    (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL);
+}
+
+status_t AudioFlinger::EffectModule::configure()
+{
+    uint32_t channels;
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return DEAD_OBJECT;
+    }
+
+    // TODO: handle configuration of effects replacing track process
+    if (thread->channelCount() == 1) {
+        channels = CHANNEL_MONO;
+    } else {
+        channels = CHANNEL_STEREO;
+    }
+
+    if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+        mConfig.inputCfg.channels = CHANNEL_MONO;
+    } else {
+        mConfig.inputCfg.channels = channels;
+    }
+    mConfig.outputCfg.channels = channels;
+    mConfig.inputCfg.format = PCM_FORMAT_S15;
+    mConfig.outputCfg.format = PCM_FORMAT_S15;
+    mConfig.inputCfg.samplingRate = thread->sampleRate();
+    mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
+    mConfig.inputCfg.bufferProvider.cookie = NULL;
+    mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+    mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+    mConfig.outputCfg.bufferProvider.cookie = NULL;
+    mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+    mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+    mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    // Insert effect:
+    // - in session 0, always overwrites output buffer: input buffer == output buffer
+    // - in other sessions:
+    //      last effect in the chain accumulates in output buffer: input buffer != output buffer
+    //      other effect: overwrites output buffer: input buffer == output buffer
+    // Auxiliary effect:
+    //      accumulates in output buffer: input buffer != output buffer
+    // Therefore: accumulate <=> input buffer != output buffer
+    if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
+        mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    } else {
+        mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+    }
+    mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+    mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+    mConfig.inputCfg.buffer.frameCount = thread->frameCount();
+    mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
+
+    status_t cmdStatus;
+    int size = sizeof(int);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::init()
+{
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t cmdStatus;
+    int size = sizeof(status_t);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_INIT, 0, NULL, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::start()
+{
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t cmdStatus;
+    int size = sizeof(status_t);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_ENABLE, 0, NULL, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::stop()
+{
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t cmdStatus;
+    int size = sizeof(status_t);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_DISABLE, 0, NULL, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
+{
+    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
+
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+    if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
+        int size = (replySize == NULL) ? 0 : *replySize;
+        Mutex::Autolock _l(mLock);
+        for (size_t i = 1; i < mHandles.size(); i++) {
+            sp<EffectHandle> h = mHandles[i].promote();
+            if (h != 0) {
+                h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData);
+            }
+        }
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+    LOGV("setEnabled %p enabled %d", this, enabled);
+
+    if (enabled != isEnabled()) {
+        switch (mState) {
+        // going from disabled to enabled
+        case IDLE:
+            mState = RESET;
+            break;
+        case STOPPING:
+            mState = ACTIVE;
+            break;
+        case STOPPED:
+            mState = STARTING;
+            break;
+
+        // going from enabled to disabled
+        case RESET:
+            mState = IDLE;
+            break;
+        case STARTING:
+            mState = STOPPED;
+            break;
+        case ACTIVE:
+            mState = STOPPING;
+            break;
+        }
+        for (size_t i = 1; i < mHandles.size(); i++) {
+            sp<EffectHandle> h = mHandles[i].promote();
+            if (h != 0) {
+                h->setEnabled(enabled);
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+bool AudioFlinger::EffectModule::isEnabled()
+{
+    switch (mState) {
+    case RESET:
+    case STARTING:
+    case ACTIVE:
+        return true;
+    case IDLE:
+    case STOPPING:
+    case STOPPED:
+    default:
+        return false;
+    }
+}
+
+status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
+{
+    status_t status = NO_ERROR;
+
+    // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
+    // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
+    if ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) & (EFFECT_FLAG_VOLUME_CTRL|EFFECT_FLAG_VOLUME_IND)) {
+        status_t cmdStatus;
+        uint32_t volume[2];
+        uint32_t *pVolume = NULL;
+        int size = sizeof(volume);
+        volume[0] = *left;
+        volume[1] = *right;
+        if (controller) {
+            pVolume = volume;
+        }
+        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_VOLUME, size, volume, &size, pVolume);
+        if (controller && status == NO_ERROR && size == sizeof(volume)) {
+            *left = volume[0];
+            *right = volume[1];
+        }
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
+{
+    status_t status = NO_ERROR;
+    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_MASK) {
+        status_t cmdStatus;
+        int size = sizeof(status_t);
+        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus);
+        if (status == NO_ERROR) {
+            status = cmdStatus;
+        }
+    }
+    return status;
+}
+
+
+status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\tEffect ID %d:\n", mId);
+    result.append(buffer);
+
+    bool locked = tryLock(mLock);
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!locked) {
+        result.append("\t\tCould not lock Fx mutex:\n");
+    }
+
+    result.append("\t\tSession Status State Engine:\n");
+    snprintf(buffer, SIZE, "\t\t%05d   %03d    %03d   0x%08x\n",
+            mSessionId, mStatus, mState, (uint32_t)mEffectInterface);
+    result.append(buffer);
+
+    result.append("\t\tDescriptor:\n");
+    snprintf(buffer, SIZE, "\t\t- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
+            mDescriptor.uuid.timeLow, mDescriptor.uuid.timeMid, mDescriptor.uuid.timeHiAndVersion,
+            mDescriptor.uuid.clockSeq, mDescriptor.uuid.node[0], mDescriptor.uuid.node[1],mDescriptor.uuid.node[2],
+            mDescriptor.uuid.node[3],mDescriptor.uuid.node[4],mDescriptor.uuid.node[5]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
+                mDescriptor.type.timeLow, mDescriptor.type.timeMid, mDescriptor.type.timeHiAndVersion,
+                mDescriptor.type.clockSeq, mDescriptor.type.node[0], mDescriptor.type.node[1],mDescriptor.type.node[2],
+                mDescriptor.type.node[3],mDescriptor.type.node[4],mDescriptor.type.node[5]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- apiVersion: %04X\n\t\t- flags: %08X\n",
+            mDescriptor.apiVersion,
+            mDescriptor.flags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- name: %s\n",
+            mDescriptor.name);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- implementor: %s\n",
+            mDescriptor.implementor);
+    result.append(buffer);
+
+    result.append("\t\t- Input configuration:\n");
+    result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n");
+    snprintf(buffer, SIZE, "\t\t\t0x%08x %05d   %05d    %08x %d\n",
+            (uint32_t)mConfig.inputCfg.buffer.raw,
+            mConfig.inputCfg.buffer.frameCount,
+            mConfig.inputCfg.samplingRate,
+            mConfig.inputCfg.channels,
+            mConfig.inputCfg.format);
+    result.append(buffer);
+
+    result.append("\t\t- Output configuration:\n");
+    result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n");
+    snprintf(buffer, SIZE, "\t\t\t0x%08x %05d   %05d    %08x %d\n",
+            (uint32_t)mConfig.outputCfg.buffer.raw,
+            mConfig.outputCfg.buffer.frameCount,
+            mConfig.outputCfg.samplingRate,
+            mConfig.outputCfg.channels,
+            mConfig.outputCfg.format);
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "\t\t%d Clients:\n", mHandles.size());
+    result.append(buffer);
+    result.append("\t\t\tPid   Priority Ctrl Locked client server\n");
+    for (size_t i = 0; i < mHandles.size(); ++i) {
+        sp<EffectHandle> handle = mHandles[i].promote();
+        if (handle != 0) {
+            handle->dump(buffer, SIZE);
+            result.append(buffer);
+        }
+    }
+
+    result.append("\n");
+
+    write(fd, result.string(), result.length());
+
+    if (locked) {
+        mLock.unlock();
+    }
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+//  EffectHandle implementation
+// ----------------------------------------------------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectHandle"
+
+AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
+                                        const sp<AudioFlinger::Client>& client,
+                                        const sp<IEffectClient>& effectClient,
+                                        int32_t priority)
+    : BnEffect(),
+    mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false)
+{
+    LOGV("constructor %p", this);
+
+    int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
+    mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
+    if (mCblkMemory != 0) {
+        mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer());
+
+        if (mCblk) {
+            new(mCblk) effect_param_cblk_t();
+            mBuffer = (uint8_t *)mCblk + bufOffset;
+         }
+    } else {
+        LOGE("not enough memory for Effect size=%u", EFFECT_PARAM_BUFFER_SIZE + sizeof(effect_param_cblk_t));
+        return;
+    }
+}
+
+AudioFlinger::EffectHandle::~EffectHandle()
+{
+    LOGV("Destructor %p", this);
+    disconnect();
+}
+
+status_t AudioFlinger::EffectHandle::enable()
+{
+    if (!mHasControl) return INVALID_OPERATION;
+    if (mEffect == 0) return DEAD_OBJECT;
+
+    return mEffect->setEnabled(true);
+}
+
+status_t AudioFlinger::EffectHandle::disable()
+{
+    if (!mHasControl) return INVALID_OPERATION;
+    if (mEffect == NULL) return DEAD_OBJECT;
+
+    return mEffect->setEnabled(false);
+}
+
+void AudioFlinger::EffectHandle::disconnect()
+{
+    if (mEffect == 0) {
+        return;
+    }
+    mEffect->disconnect(this);
+    // release sp on module => module destructor can be called now
+    mEffect.clear();
+    if (mCblk) {
+        mCblk->~effect_param_cblk_t();   // destroy our shared-structure.
+    }
+    mCblkMemory.clear();            // and free the shared memory
+    if (mClient != 0) {
+        Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        mClient.clear();
+    }
+}
+
+status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
+{
+    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+
+    // only get parameter command is permitted for applications not controlling the effect
+    if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
+        return INVALID_OPERATION;
+    }
+    if (mEffect == 0) return DEAD_OBJECT;
+
+    // handle commands that are not forwarded transparently to effect engine
+    if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
+        // No need to trylock() here as this function is executed in the binder thread serving a particular client process:
+        // no risk to block the whole media server process or mixer threads is we are stuck here
+        Mutex::Autolock _l(mCblk->lock);
+        if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
+            mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
+            mCblk->serverIndex = 0;
+            mCblk->clientIndex = 0;
+            return BAD_VALUE;
+        }
+        status_t status = NO_ERROR;
+        while (mCblk->serverIndex < mCblk->clientIndex) {
+            int reply;
+            int rsize = sizeof(int);
+            int *p = (int *)(mBuffer + mCblk->serverIndex);
+            int size = *p++;
+            effect_param_t *param = (effect_param_t *)p;
+            int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
+            status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, psize, p, &rsize, &reply);
+            if (ret == NO_ERROR) {
+                if (reply != NO_ERROR) {
+                    status = reply;
+                }
+            } else {
+                status = ret;
+            }
+            mCblk->serverIndex += size;
+        }
+        mCblk->serverIndex = 0;
+        mCblk->clientIndex = 0;
+        return status;
+    } else if (cmdCode == EFFECT_CMD_ENABLE) {
+        return enable();
+    } else if (cmdCode == EFFECT_CMD_DISABLE) {
+        return disable();
+    }
+
+    return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+}
+
+sp<IMemory> AudioFlinger::EffectHandle::getCblk() const {
+    return mCblkMemory;
+}
+
+void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal)
+{
+    LOGV("setControl %p control %d", this, hasControl);
+
+    mHasControl = hasControl;
+    if (signal && mEffectClient != 0) {
+        mEffectClient->controlStatusChanged(hasControl);
+    }
+}
+
+void AudioFlinger::EffectHandle::commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData)
+{
+    if (mEffectClient != 0) {
+        mEffectClient->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+    }
+}
+
+
+
+void AudioFlinger::EffectHandle::setEnabled(bool enabled)
+{
+    if (mEffectClient != 0) {
+        mEffectClient->enableStatusChanged(enabled);
+    }
+}
+
+status_t AudioFlinger::EffectHandle::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnEffect::onTransact(code, data, reply, flags);
+}
+
+
+void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
+{
+    bool locked = tryLock(mCblk->lock);
+
+    snprintf(buffer, size, "\t\t\t%05d %05d    %01u    %01u      %05u  %05u\n",
+            (mClient == NULL) ? getpid() : mClient->pid(),
+            mPriority,
+            mHasControl,
+            !locked,
+            mCblk->clientIndex,
+            mCblk->serverIndex
+            );
+
+    if (locked) {
+        mCblk->lock.unlock();
+    }
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectChain"
+
+AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
+                                        int sessionId)
+    : mThread(wThread), mSessionId(sessionId), mVolumeCtrlIdx(-1), mActiveTrackCnt(0), mOwnInBuffer(false)
+{
+
+}
+
+AudioFlinger::EffectChain::~EffectChain()
+{
+    if (mOwnInBuffer) {
+        delete mInBuffer;
+    }
+
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc(effect_descriptor_t *descriptor)
+{
+    sp<EffectModule> effect;
+    size_t size = mEffects.size();
+
+    for (size_t i = 0; i < size; i++) {
+        if (memcmp(&mEffects[i]->desc().uuid, &descriptor->uuid, sizeof(effect_uuid_t)) == 0) {
+            effect = mEffects[i];
+            break;
+        }
+    }
+    return effect;
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId(int id)
+{
+    sp<EffectModule> effect;
+    size_t size = mEffects.size();
+
+    for (size_t i = 0; i < size; i++) {
+        if (mEffects[i]->id() == id) {
+            effect = mEffects[i];
+            break;
+        }
+    }
+    return effect;
+}
+
+// Must be called with EffectChain::mLock locked
+void AudioFlinger::EffectChain::process_l()
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->process();
+    }
+    // if no track is active, input buffer must be cleared here as the mixer process
+    // will not do it
+    if (mSessionId != 0 && activeTracks() == 0) {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            size_t numSamples = thread->frameCount() * thread->channelCount();
+            memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+        }
+    }
+}
+
+status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect)
+{
+    effect_descriptor_t desc = effect->desc();
+    uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
+
+    Mutex::Autolock _l(mLock);
+
+    if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+        // Auxiliary effects are inserted at the beginning of mEffects vector as
+        // they are processed first and accumulated in chain input buffer
+        mEffects.insertAt(effect, 0);
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread == 0) {
+            return NO_INIT;
+        }
+        // the input buffer for auxiliary effect contains mono samples in
+        // 32 bit format. This is to avoid saturation in AudoMixer
+        // accumulation stage. Saturation is done in EffectModule::process() before
+        // calling the process in effect engine
+        size_t numSamples = thread->frameCount();
+        int32_t *buffer = new int32_t[numSamples];
+        memset(buffer, 0, numSamples * sizeof(int32_t));
+        effect->setInBuffer((int16_t *)buffer);
+        // auxiliary effects output samples to chain input buffer for further processing
+        // by insert effects
+        effect->setOutBuffer(mInBuffer);
+    } else {
+        // Insert effects are inserted at the end of mEffects vector as they are processed
+        //  after track and auxiliary effects.
+        // Insert effect order:
+        //  if EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_EXCLUSIVE insert as first insert effect
+        //  else if EFFECT_FLAG_INSERT_ANY insert after first or before last
+        //  else insert as last insert effect
+        // Reject insertion if:
+        //  - EFFECT_FLAG_INSERT_EXCLUSIVE and another effect is present
+        //  - an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is present
+        //  - EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_LAST and an effect with same
+        //  preference is present
+
+        int size = (int)mEffects.size();
+        int idx_insert = size;
+        int idx_insert_first = -1;
+        int idx_insert_last = -1;
+
+        for (int i = 0; i < size; i++) {
+            effect_descriptor_t d = mEffects[i]->desc();
+            uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK;
+            uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK;
+            if (iMode == EFFECT_FLAG_TYPE_INSERT) {
+                // check invalid effect chaining combinations
+                if (insertPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
+                    iPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
+                    (insertPref != EFFECT_FLAG_INSERT_ANY
+                                && insertPref == iPref)) {
+                    return INVALID_OPERATION;
+                }
+                // remember position of first insert effect
+                if (idx_insert == size) {
+                    idx_insert = i;
+                }
+                // remember position of insert effect claiming
+                // first place
+                if (iPref == EFFECT_FLAG_INSERT_FIRST) {
+                    idx_insert_first = i;
+                }
+                // remember position of insert effect claiming
+                // last place
+                if (iPref == EFFECT_FLAG_INSERT_LAST) {
+                    idx_insert_last = i;
+                }
+            }
+        }
+
+        // modify idx_insert from first place if needed
+        if (idx_insert_first != -1) {
+            idx_insert = idx_insert_first + 1;
+        } else if (idx_insert_last != -1) {
+            idx_insert = idx_insert_last;
+        } else if (insertPref == EFFECT_FLAG_INSERT_LAST) {
+            idx_insert = size;
+        }
+
+        // always read samples from chain input buffer
+        effect->setInBuffer(mInBuffer);
+
+        // if last effect in the chain, output samples to chain
+        // output buffer, otherwise to chain input buffer
+        if (idx_insert == size) {
+            if (idx_insert != 0) {
+                mEffects[idx_insert-1]->setOutBuffer(mInBuffer);
+                mEffects[idx_insert-1]->configure();
+            }
+            effect->setOutBuffer(mOutBuffer);
+        } else {
+            effect->setOutBuffer(mInBuffer);
+        }
+        status_t status = mEffects.insertAt(effect, idx_insert);
+        // Always give volume control to last effect in chain with volume control capability
+        if (((desc.flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) &&
+                mVolumeCtrlIdx < idx_insert) {
+            mVolumeCtrlIdx = idx_insert;
+        }
+
+        LOGV("addEffect() effect %p, added in chain %p at rank %d status %d", effect.get(), this, idx_insert, status);
+    }
+    effect->configure();
+    return NO_ERROR;
+}
+
+size_t AudioFlinger::EffectChain::removeEffect(const sp<EffectModule>& effect)
+{
+    Mutex::Autolock _l(mLock);
+
+    int size = (int)mEffects.size();
+    int i;
+    uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK;
+
+    for (i = 0; i < size; i++) {
+        if (effect == mEffects[i]) {
+            if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
+                delete[] effect->inBuffer();
+            } else {
+                if (i == size - 1 && i != 0) {
+                    mEffects[i - 1]->setOutBuffer(mOutBuffer);
+                    mEffects[i - 1]->configure();
+                }
+            }
+            mEffects.removeAt(i);
+            LOGV("removeEffect() effect %p, removed from chain %p at rank %d", effect.get(), this, i);
+            break;
+        }
+    }
+    // Return volume control to last effect in chain with volume control capability
+    if (mVolumeCtrlIdx == i) {
+        size = (int)mEffects.size();
+        for (i = size; i > 0; i--) {
+            if ((mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) {
+                break;
+            }
+        }
+        // mVolumeCtrlIdx reset to -1 if no effect found with volume control flag set
+        mVolumeCtrlIdx = i - 1;
+    }
+
+    return mEffects.size();
+}
+
+void AudioFlinger::EffectChain::setDevice(uint32_t device)
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->setDevice(device);
+    }
+}
+
+bool AudioFlinger::EffectChain::setVolume(uint32_t *left, uint32_t *right)
+{
+    uint32_t newLeft = *left;
+    uint32_t newRight = *right;
+    bool hasControl = false;
+
+    // first get volume update from volume controller
+    if (mVolumeCtrlIdx >= 0) {
+        mEffects[mVolumeCtrlIdx]->setVolume(&newLeft, &newRight, true);
+        hasControl = true;
+    }
+    // then indicate volume to all other effects in chain.
+    // Pass altered volume to effects before volume controller
+    // and requested volume to effects after controller
+    uint32_t lVol = newLeft;
+    uint32_t rVol = newRight;
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        if ((int)i == mVolumeCtrlIdx) continue;
+        // this also works for mVolumeCtrlIdx == -1 when there is no volume controller
+        if ((int)i > mVolumeCtrlIdx) {
+            lVol = *left;
+            rVol = *right;
+        }
+        mEffects[i]->setVolume(&lVol, &rVol, false);
+    }
+    *left = newLeft;
+    *right = newRight;
+
+    return hasControl;
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getVolumeController()
+{
+    sp<EffectModule> effect;
+    if (mVolumeCtrlIdx >= 0) {
+        effect = mEffects[mVolumeCtrlIdx];
+    }
+    return effect;
+}
+
+
+status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Effects for session %d:\n", mSessionId);
+    result.append(buffer);
+
+    bool locked = tryLock(mLock);
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!locked) {
+        result.append("\tCould not lock mutex:\n");
+    }
+
+    result.append("\tNum fx In buffer   Out buffer   Vol ctrl Active tracks:\n");
+    snprintf(buffer, SIZE, "\t%02d     0x%08x  0x%08x   %02d       %d\n",
+            mEffects.size(),
+            (uint32_t)mInBuffer,
+            (uint32_t)mOutBuffer,
+            (mVolumeCtrlIdx == -1) ? 0 : mEffects[mVolumeCtrlIdx]->id(),
+            mActiveTrackCnt);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    for (size_t i = 0; i < mEffects.size(); ++i) {
+        sp<EffectModule> effect = mEffects[i];
+        if (effect != 0) {
+            effect->dump(fd, args);
+        }
+    }
+
+    if (locked) {
+        mLock.unlock();
+    }
+
+    return NO_ERROR;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger"
+
 // ----------------------------------------------------------------------------
 
 status_t AudioFlinger::onTransact(
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index f35f38b..e543334 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -42,6 +42,7 @@
 namespace android {
 
 class audio_track_cblk_t;
+class effect_param_cblk_t;
 class AudioMixer;
 class AudioBuffer;
 class AudioResampler;
@@ -75,6 +76,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 int output,
+                                int *sessionId,
                                 status_t *status);
 
     virtual     uint32_t    sampleRate(int output) const;
@@ -139,6 +141,28 @@
 
     virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
 
+    virtual int newAudioSessionId();
+
+    virtual status_t loadEffectLibrary(const char *libPath, int *handle);
+
+    virtual status_t unloadEffectLibrary(int handle);
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects);
+
+    virtual status_t queryNextEffect(effect_descriptor_t *descriptor);
+
+    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                        effect_descriptor_t *pDesc,
+                        const sp<IEffectClient>& effectClient,
+                        int32_t priority,
+                        int output,
+                        int sessionId,
+                        status_t *status,
+                        int *id,
+                        int *enabled);
+
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
         AUDIO_HW_INIT,
@@ -167,6 +191,7 @@
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
+                                int *sessionId,
                                 status_t *status);
 
     virtual     status_t    onTransact(
@@ -233,6 +258,9 @@
     class DuplicatingThread;
     class Track;
     class RecordTrack;
+    class EffectModule;
+    class EffectHandle;
+    class EffectChain;
 
     class ThreadBase : public Thread {
     public:
@@ -268,13 +296,15 @@
                                         int channelCount,
                                         int frameCount,
                                         uint32_t flags,
-                                        const sp<IMemory>& sharedBuffer);
+                                        const sp<IMemory>& sharedBuffer,
+                                        int sessionId);
                                 ~TrackBase();
 
             virtual status_t    start() = 0;
             virtual void        stop() = 0;
                     sp<IMemory> getCblk() const;
                     audio_track_cblk_t* cblk() const { return mCblk; }
+                    int         sessionId() { return mSessionId; }
 
         protected:
             friend class ThreadBase;
@@ -323,6 +353,7 @@
             int                 mClientTid;
             uint8_t             mFormat;
             uint32_t            mFlags;
+            int                 mSessionId;
         };
 
         class ConfigEvent {
@@ -405,7 +436,8 @@
                                         int format,
                                         int channelCount,
                                         int frameCount,
-                                        const sp<IMemory>& sharedBuffer);
+                                        const sp<IMemory>& sharedBuffer,
+                                        int sessionId);
                                 ~Track();
 
                     void        dump(char* buffer, size_t size);
@@ -424,6 +456,12 @@
                     int type() const {
                         return mStreamType;
                     }
+                    status_t    attachAuxEffect(int EffectId);
+                    void        setAuxBuffer(int EffectId, int32_t *buffer);
+                    int32_t     *auxBuffer() { return mAuxBuffer; }
+                    void        setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
+                    int16_t     *mainBuffer() { return mMainBuffer; }
+                    int         auxEffectId() { return mAuxEffectId; }
 
 
         protected:
@@ -464,6 +502,9 @@
             bool                mResetDone;
             int                 mStreamType;
             int                 mName;
+            int16_t             *mMainBuffer;
+            int32_t             *mAuxBuffer;
+            int                 mAuxEffectId;
         };  // end of Track
 
 
@@ -505,7 +546,7 @@
             DuplicatingThread*          mSourceThread;
         };  // end of OutputTrack
 
-        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
+        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         virtual             ~PlaybackThread();
 
         virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -538,6 +579,7 @@
                                     int channelCount,
                                     int frameCount,
                                     const sp<IMemory>& sharedBuffer,
+                                    int sessionId,
                                     status_t *status);
 
                     AudioStreamOut* getOutput() { return mOutput; }
@@ -549,6 +591,29 @@
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged_l(int event, int param = 0);
         virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
+                    int16_t     *mixBuffer() { return mMixBuffer; };
+
+                    sp<EffectHandle> createEffect_l(
+                                        const sp<AudioFlinger::Client>& client,
+                                        const sp<IEffectClient>& effectClient,
+                                        int32_t priority,
+                                        int sessionId,
+                                        effect_descriptor_t *desc,
+                                        int *enabled,
+                                        status_t *status);
+
+                    bool hasAudioSession(int sessionId);
+                    sp<EffectChain> getEffectChain(int sessionId);
+                    sp<EffectChain> getEffectChain_l(int sessionId);
+                    status_t addEffectChain_l(const sp<EffectChain>& chain);
+                    size_t removeEffectChain_l(const sp<EffectChain>& chain);
+                    void lockEffectChains_l();
+                    void unlockEffectChains();
+
+                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
+                    void detachAuxEffect_l(int effectId);
+                    status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
+                    status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
 
         struct  stream_type_t {
             stream_type_t()
@@ -591,8 +656,11 @@
 
         void        readOutputParameters();
 
+        uint32_t    device() { return mDevice; }
+
         virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
         status_t    dumpTracks(int fd, const Vector<String16>& args);
+        status_t    dumpEffectChains(int fd, const Vector<String16>& args);
 
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
@@ -603,11 +671,13 @@
         int                             mNumWrites;
         int                             mNumDelayedWrites;
         bool                            mInWrite;
+        Vector< sp<EffectChain> >       mEffectChains;
+        uint32_t                        mDevice;
     };
 
     class MixerThread : public PlaybackThread {
     public:
-        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
+        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         virtual             ~MixerThread();
 
         // Thread virtuals
@@ -630,7 +700,7 @@
     class DirectOutputThread : public PlaybackThread {
     public:
 
-        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
+        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         ~DirectOutputThread();
 
         // Thread virtuals
@@ -645,8 +715,12 @@
         virtual     uint32_t    idleSleepTimeUs();
 
     private:
-        float mLeftVolume;
-        float mRightVolume;
+        void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
+
+        float mLeftVolFloat;
+        float mRightVolFloat;
+        uint16_t mLeftVolShort;
+        uint16_t mRightVolShort;
     };
 
     class DuplicatingThread : public MixerThread {
@@ -676,6 +750,8 @@
               float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
               void audioConfigChanged_l(int event, int ioHandle, void *param2);
 
+              int  nextUniqueId();
+
     friend class AudioBuffer;
 
     class TrackHandle : public android::BnAudioTrack {
@@ -689,6 +765,7 @@
         virtual void        pause();
         virtual void        setVolume(float left, float right);
         virtual sp<IMemory> getCblk() const;
+        virtual status_t    attachAuxEffect(int effectId);
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
@@ -717,7 +794,8 @@
                                         int format,
                                         int channelCount,
                                         int frameCount,
-                                        uint32_t flags);
+                                        uint32_t flags,
+                                        int sessionId);
                                 ~RecordTrack();
 
             virtual status_t    start();
@@ -792,6 +870,215 @@
         sp<RecordThread::RecordTrack> mRecordTrack;
     };
 
+    //--- Audio Effect Management
+
+    // EffectModule and EffectChain classes both have their own mutex to protect
+    // state changes or resource modifications. Always respect the following order
+    // if multiple mutexes must be acquired to avoid cross deadlock:
+    // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
+
+    // The EffectModule class is a wrapper object controlling the effect engine implementation
+    // in the effect library. It prevents concurrent calls to process() and command() functions
+    // from different client threads. It keeps a list of EffectHandle objects corresponding
+    // to all client applications using this effect and notifies applications of effect state,
+    // control or parameter changes. It manages the activation state machine to send appropriate
+    // reset, enable, disable commands to effect engine and provide volume
+    // ramping when effects are activated/deactivated.
+    // When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
+    // the attached track(s) to accumulate their auxiliary channel.
+    class EffectModule: public RefBase {
+    public:
+        EffectModule(const wp<ThreadBase>& wThread,
+                        const wp<AudioFlinger::EffectChain>& chain,
+                        effect_descriptor_t *desc,
+                        int id,
+                        int sessionId);
+        ~EffectModule();
+
+        enum effect_state {
+            IDLE,
+            RESET,
+            STARTING,
+            ACTIVE,
+            STOPPING,
+            STOPPED
+        };
+
+        int         id() { return mId; }
+        void process();
+        status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
+
+        void reset();
+        status_t configure();
+        status_t init();
+        uint32_t state() {
+            return mState;
+        }
+        uint32_t status() {
+            return mStatus;
+        }
+        status_t    setEnabled(bool enabled);
+        bool isEnabled();
+
+        void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
+        int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
+        void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
+        int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
+
+        status_t addHandle(sp<EffectHandle>& handle);
+        void disconnect(const wp<EffectHandle>& handle);
+        size_t removeHandle (const wp<EffectHandle>& handle);
+
+        effect_descriptor_t& desc() { return mDescriptor; }
+
+        status_t         setDevice(uint32_t device);
+        status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
+
+        status_t         dump(int fd, const Vector<String16>& args);
+
+    protected:
+
+        EffectModule(const EffectModule&);
+        EffectModule& operator = (const EffectModule&);
+
+        status_t start();
+        status_t stop();
+
+        Mutex               mLock;      // mutex for process, commands and handles list protection
+        wp<ThreadBase>      mThread;    // parent thread
+        wp<EffectChain>     mChain;     // parent effect chain
+        int                 mId;        // this instance unique ID
+        int                 mSessionId; // audio session ID
+        effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
+        effect_config_t     mConfig;    // input and output audio configuration
+        effect_interface_t  mEffectInterface; // Effect module C API
+        status_t mStatus;               // initialization status
+        uint32_t mState;                // current activation state (effect_state)
+        Vector< wp<EffectHandle> > mHandles;    // list of client handles
+    };
+
+    // The EffectHandle class implements the IEffect interface. It provides resources
+    // to receive parameter updates, keeps track of effect control
+    // ownership and state and has a pointer to the EffectModule object it is controlling.
+    // There is one EffectHandle object for each application controlling (or using)
+    // an effect module.
+    // The EffectHandle is obtained by calling AudioFlinger::createEffect().
+    class EffectHandle: public android::BnEffect {
+    public:
+
+        EffectHandle(const sp<EffectModule>& effect,
+                const sp<AudioFlinger::Client>& client,
+                const sp<IEffectClient>& effectClient,
+                int32_t priority);
+        virtual ~EffectHandle();
+
+        // IEffect
+        virtual status_t enable();
+        virtual status_t disable();
+        virtual status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
+        virtual void disconnect();
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t onTransact(uint32_t code, const Parcel& data,
+                Parcel* reply, uint32_t flags);
+
+
+        // Give or take control of effect module
+        void setControl(bool hasControl, bool signal);
+        void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData);
+        void setEnabled(bool enabled);
+
+        // Getters
+        int id() { return mEffect->id(); }
+        int priority() { return mPriority; }
+        bool hasControl() { return mHasControl; }
+        sp<EffectModule> effect() { return mEffect; }
+
+        void dump(char* buffer, size_t size);
+
+    protected:
+
+        EffectHandle(const EffectHandle&);
+        EffectHandle& operator =(const EffectHandle&);
+
+        sp<EffectModule> mEffect;           // pointer to controlled EffectModule
+        sp<IEffectClient> mEffectClient;    // callback interface for client notifications
+        sp<Client>          mClient;        // client for shared memory allocation
+        sp<IMemory>         mCblkMemory;    // shared memory for control block
+        effect_param_cblk_t* mCblk;         // control block for deferred parameter setting via shared memory
+        uint8_t*            mBuffer;        // pointer to parameter area in shared memory
+        int mPriority;                      // client application priority to control the effect
+        bool mHasControl;                   // true if this handle is controlling the effect
+    };
+
+    // the EffectChain class represents a group of effects associated to one audio session.
+    // There can be any number of EffectChain objects per output mixer thread (PlaybackThread).
+    // The EffecChain with session ID 0 contains global effects applied to the output mix.
+    // Effects in this chain can be insert or auxiliary. Effects in other chains (attached to tracks)
+    // are insert only. The EffectChain maintains an ordered list of effect module, the order corresponding
+    // in the effect process order. When attached to a track (session ID != 0), it also provide it's own
+    // input buffer used by the track as accumulation buffer.
+    class EffectChain: public RefBase {
+    public:
+        EffectChain(const wp<ThreadBase>& wThread, int sessionId);
+        ~EffectChain();
+
+        void process_l();
+
+        void lock() {
+            mLock.lock();
+        }
+        void unlock() {
+            mLock.unlock();
+        }
+
+        status_t addEffect(sp<EffectModule>& handle);
+        size_t removeEffect(const sp<EffectModule>& handle);
+
+        int sessionId() {
+            return mSessionId;
+        }
+        sp<EffectModule> getEffectFromDesc(effect_descriptor_t *descriptor);
+        sp<EffectModule> getEffectFromId(int id);
+        sp<EffectModule> getVolumeController();
+        bool setVolume(uint32_t *left, uint32_t *right);
+        void setDevice(uint32_t device);
+
+        void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
+            mInBuffer = buffer;
+            mOwnInBuffer = ownsBuffer;
+        }
+        int16_t *inBuffer() {
+            return mInBuffer;
+        }
+        void setOutBuffer(int16_t *buffer) {
+            mOutBuffer = buffer;
+        }
+        int16_t *outBuffer() {
+            return mOutBuffer;
+        }
+
+        void startTrack() {mActiveTrackCnt++;}
+        void stopTrack() {mActiveTrackCnt--;}
+        int activeTracks() { return mActiveTrackCnt;}
+
+        status_t dump(int fd, const Vector<String16>& args);
+
+    protected:
+
+        EffectChain(const EffectChain&);
+        EffectChain& operator =(const EffectChain&);
+
+        wp<ThreadBase> mThread;     // parent mixer thread
+        Mutex mLock;                // mutex protecting effect list
+        Vector<sp<EffectModule> > mEffects; // list of effect modules
+        int mSessionId;             // audio session ID
+        int16_t *mInBuffer;         // chain input buffer
+        int16_t *mOutBuffer;        // chain output buffer
+        int mVolumeCtrlIdx;         // index of insert effect having control over volume
+        int mActiveTrackCnt;        // number of active tracks connected
+        bool mOwnInBuffer;          // true if the chain owns its input buffer
+    };
+
     friend class RecordThread;
     friend class PlaybackThread;
 
@@ -813,7 +1100,7 @@
                 DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads;
 
                 DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
-                int                                 mNextThreadId;
+                volatile int32_t                    mNextUniqueId;
 #ifdef LVMX
                 int mLifeVibesClientPid;
 #endif
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 19a442a8..8aaa325 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -56,6 +56,8 @@
         t->volume[1] = UNITY_GAIN;
         t->volumeInc[0] = 0;
         t->volumeInc[1] = 0;
+        t->auxLevel = 0;
+        t->auxInc = 0;
         t->channelCount = 2;
         t->enabled = 0;
         t->format = 16;
@@ -65,6 +67,8 @@
         t->resampler = 0;
         t->sampleRate = mSampleRate;
         t->in = 0;
+        t->mainBuffer = NULL;
+        t->auxBuffer = NULL;
         t++;
     }
 }
@@ -169,28 +173,48 @@
     return NO_ERROR;
 }
 
-status_t AudioMixer::setParameter(int target, int name, int value)
+status_t AudioMixer::setParameter(int target, int name, void *value)
 {
+    int valueInt = (int)value;
+    int32_t *valueBuf = (int32_t *)value;
+
     switch (target) {
     case TRACK:
         if (name == CHANNEL_COUNT) {
-            if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
-                if (mState.tracks[ mActiveTrack ].channelCount != value) {
-                    mState.tracks[ mActiveTrack ].channelCount = value;
-                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
+            if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) {
+                if (mState.tracks[ mActiveTrack ].channelCount != valueInt) {
+                    mState.tracks[ mActiveTrack ].channelCount = valueInt;
+                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt);
                     invalidateState(1<<mActiveTrack);
                 }
                 return NO_ERROR;
             }
         }
+        if (name == MAIN_BUFFER) {
+            if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
+                mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
+                LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        }
+        if (name == AUX_BUFFER) {
+            if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) {
+                mState.tracks[ mActiveTrack ].auxBuffer = valueBuf;
+                LOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        }
+
         break;
     case RESAMPLE:
         if (name == SAMPLE_RATE) {
-            if (value > 0) {
+            if (valueInt > 0) {
                 track_t& track = mState.tracks[ mActiveTrack ];
-                if (track.setResampler(uint32_t(value), mSampleRate)) {
+                if (track.setResampler(uint32_t(valueInt), mSampleRate)) {
                     LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
-                            uint32_t(value));
+                            uint32_t(valueInt));
                     invalidateState(1<<mActiveTrack);
                 }
                 return NO_ERROR;
@@ -201,18 +225,39 @@
     case VOLUME:
         if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
             track_t& track = mState.tracks[ mActiveTrack ];
-            if (track.volume[name-VOLUME0] != value) {
+            if (track.volume[name-VOLUME0] != valueInt) {
+                LOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);
                 track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
-                track.volume[name-VOLUME0] = value;
+                track.volume[name-VOLUME0] = valueInt;
                 if (target == VOLUME) {
-                    track.prevVolume[name-VOLUME0] = value << 16;
+                    track.prevVolume[name-VOLUME0] = valueInt << 16;
                     track.volumeInc[name-VOLUME0] = 0;
                 } else {
-                    int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
+                    int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0];
                     int32_t volInc = d / int32_t(mState.frameCount);
                     track.volumeInc[name-VOLUME0] = volInc;
                     if (volInc == 0) {
-                        track.prevVolume[name-VOLUME0] = value << 16;
+                        track.prevVolume[name-VOLUME0] = valueInt << 16;
+                    }
+                }
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        } else if (name == AUXLEVEL) {
+            track_t& track = mState.tracks[ mActiveTrack ];
+            if (track.auxLevel != valueInt) {
+                LOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
+                track.prevAuxLevel = track.auxLevel << 16;
+                track.auxLevel = valueInt;
+                if (target == VOLUME) {
+                    track.prevAuxLevel = valueInt << 16;
+                    track.auxInc = 0;
+                } else {
+                    int32_t d = (valueInt<<16) - track.prevAuxLevel;
+                    int32_t volInc = d / int32_t(mState.frameCount);
+                    track.auxInc = volInc;
+                    if (volInc == 0) {
+                        track.prevAuxLevel = valueInt << 16;
                     }
                 }
                 invalidateState(1<<mActiveTrack);
@@ -245,7 +290,7 @@
 }
 
 inline
-void AudioMixer::track_t::adjustVolumeRamp()
+void AudioMixer::track_t::adjustVolumeRamp(bool aux)
 {
     for (int i=0 ; i<2 ; i++) {
         if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
@@ -254,6 +299,13 @@
             prevVolume[i] = volume[i]<<16;
         }
     }
+    if (aux) {
+        if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) ||
+            ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) {
+            auxInc = 0;
+            prevAuxLevel = auxLevel<<16;
+        }
+    }
 }
 
 
@@ -265,13 +317,13 @@
 
 
 
-void AudioMixer::process(void* output)
+void AudioMixer::process()
 {
-    mState.hook(&mState, output);
+    mState.hook(&mState);
 }
 
 
-void AudioMixer::process__validate(state_t* state, void* output)
+void AudioMixer::process__validate(state_t* state)
 {
     LOGW_IF(!state->needsChanged,
         "in process__validate() but nothing's invalid");
@@ -308,7 +360,10 @@
         n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
         n |= NEEDS_FORMAT_16;
         n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
-       
+        if (t.auxLevel != 0 && t.auxBuffer != NULL) {
+            n |= NEEDS_AUX_ENABLED;
+        }
+
         if (t.volumeInc[0]|t.volumeInc[1]) {
             volumeRamp = 1;
         } else if (!t.doesResample() && t.volumeRL == 0) {
@@ -319,6 +374,9 @@
         if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
             t.hook = track__nop;
         } else {
+            if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+                all16BitsStereoNoResample = 0;
+            }
             if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
                 all16BitsStereoNoResample = 0;
                 resampling = 1;
@@ -369,7 +427,7 @@
         countActiveTracks, state->enabledTracks,
         all16BitsStereoNoResample, resampling, volumeRamp);
 
-   state->hook(state, output);
+   state->hook(state);
 
    // Now that the volume ramp has been done, set optimal state and
    // track hooks for subsequent mixer process
@@ -390,7 +448,7 @@
        }
        if (allMuted) {
            state->hook = process__nop;
-       } else if (!resampling && all16BitsStereoNoResample) {
+       } else if (all16BitsStereoNoResample) {
            if (countActiveTracks == 1) {
               state->hook = process__OneTrack16BitsStereoNoResampling;
            }
@@ -481,30 +539,44 @@
 }
 
 
-void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
 {
     t->resampler->setSampleRate(t->sampleRate);
 
     // ramp gain - resample to temp buffer and scale/mix in 2nd step
-    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+    if (aux != NULL) {
+        // always resample with unity gain when sending to auxiliary buffer to be able
+        // to apply send level after resampling
+        // TODO: modify each resampler to support aux channel?
         t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
         memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
         t->resampler->resample(temp, outFrameCount, t->bufferProvider);
-        volumeRampStereo(t, out, outFrameCount, temp);
-    }
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
+            volumeRampStereo(t, out, outFrameCount, temp, aux);
+        } else {
+            volumeStereo(t, out, outFrameCount, temp, aux);
+        }
+    } else {
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+            t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+            memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+            t->resampler->resample(temp, outFrameCount, t->bufferProvider);
+            volumeRampStereo(t, out, outFrameCount, temp, aux);
+        }
 
-    // constant gain
-    else {
-        t->resampler->setVolume(t->volume[0], t->volume[1]);
-        t->resampler->resample(out, outFrameCount, t->bufferProvider);
+        // constant gain
+        else {
+            t->resampler->setVolume(t->volume[0], t->volume[1]);
+            t->resampler->resample(out, outFrameCount, t->bufferProvider);
+        }
     }
 }
 
-void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
 {
 }
 
-void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
 {
     int32_t vl = t->prevVolume[0];
     int32_t vr = t->prevVolume[1];
@@ -514,98 +586,238 @@
     //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
     //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
     //       (vl + vlInc*frameCount)/65536.0f, frameCount);
-   
+
     // ramp volume
-    do {
-        *out++ += (vl >> 16) * (*temp++ >> 12);
-        *out++ += (vr >> 16) * (*temp++ >> 12);
-        vl += vlInc;
-        vr += vrInc;
-    } while (--frameCount);
-
-    t->prevVolume[0] = vl;
-    t->prevVolume[1] = vr;
-    t->adjustVolumeRamp();
-}
-
-void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
-{
-    int16_t const *in = static_cast<int16_t const *>(t->in);
-
-    // ramp gain
-    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
-        int32_t vl = t->prevVolume[0];
-        int32_t vr = t->prevVolume[1];
-        const int32_t vlInc = t->volumeInc[0];
-        const int32_t vrInc = t->volumeInc[1];
-
-        // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
-        //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
-        //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+    if UNLIKELY(aux != NULL) {
+        int32_t va = t->prevAuxLevel;
+        const int32_t vaInc = t->auxInc;
+        int32_t l;
+        int32_t r;
 
         do {
-            *out++ += (vl >> 16) * (int32_t) *in++;
-            *out++ += (vr >> 16) * (int32_t) *in++;
+            l = (*temp++ >> 12);
+            r = (*temp++ >> 12);
+            *out++ += (vl >> 16) * l;
+            *out++ += (vr >> 16) * r;
+            *aux++ += (va >> 17) * (l + r);
+            vl += vlInc;
+            vr += vrInc;
+            va += vaInc;
+        } while (--frameCount);
+        t->prevAuxLevel = va;
+    } else {
+        do {
+            *out++ += (vl >> 16) * (*temp++ >> 12);
+            *out++ += (vr >> 16) * (*temp++ >> 12);
             vl += vlInc;
             vr += vrInc;
         } while (--frameCount);
-       
-        t->prevVolume[0] = vl;
-        t->prevVolume[1] = vr;
-        t->adjustVolumeRamp();
     }
+    t->prevVolume[0] = vl;
+    t->prevVolume[1] = vr;
+    t->adjustVolumeRamp((aux != NULL));
+}
 
-    // constant gain
-    else {
-        const uint32_t vrl = t->volumeRL;
+void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
+{
+    const int16_t vl = t->volume[0];
+    const int16_t vr = t->volume[1];
+
+    if UNLIKELY(aux != NULL) {
+        const int16_t va = (int16_t)t->auxLevel;
         do {
-            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
-            in += 2;
-            out[0] = mulAddRL(1, rl, vrl, out[0]);
-            out[1] = mulAddRL(0, rl, vrl, out[1]);
+            int16_t l = (int16_t)(*temp++ >> 12);
+            int16_t r = (int16_t)(*temp++ >> 12);
+            out[0] = mulAdd(l, vl, out[0]);
+            int16_t a = (int16_t)(((int32_t)l + r) >> 1);
+            out[1] = mulAdd(r, vr, out[1]);
+            out += 2;
+            aux[0] = mulAdd(a, va, aux[0]);
+            aux++;
+        } while (--frameCount);
+    } else {
+        do {
+            int16_t l = (int16_t)(*temp++ >> 12);
+            int16_t r = (int16_t)(*temp++ >> 12);
+            out[0] = mulAdd(l, vl, out[0]);
+            out[1] = mulAdd(r, vr, out[1]);
             out += 2;
         } while (--frameCount);
     }
+}
+
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
+{
+    int16_t const *in = static_cast<int16_t const *>(t->in);
+
+    if UNLIKELY(aux != NULL) {
+        int32_t l;
+        int32_t r;
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            int32_t va = t->prevAuxLevel;
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+            const int32_t vaInc = t->auxInc;
+            // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+            do {
+                l = (int32_t)*in++;
+                r = (int32_t)*in++;
+                *out++ += (vl >> 16) * l;
+                *out++ += (vr >> 16) * r;
+                *aux++ += (va >> 17) * (l + r);
+                vl += vlInc;
+                vr += vrInc;
+                va += vaInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->prevAuxLevel = va;
+            t->adjustVolumeRamp(true);
+        }
+
+        // constant gain
+        else {
+            const uint32_t vrl = t->volumeRL;
+            const int16_t va = (int16_t)t->auxLevel;
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
+                in += 2;
+                out[0] = mulAddRL(1, rl, vrl, out[0]);
+                out[1] = mulAddRL(0, rl, vrl, out[1]);
+                out += 2;
+                aux[0] = mulAdd(a, va, aux[0]);
+                aux++;
+            } while (--frameCount);
+        }
+    } else {
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+
+            // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+            do {
+                *out++ += (vl >> 16) * (int32_t) *in++;
+                *out++ += (vr >> 16) * (int32_t) *in++;
+                vl += vlInc;
+                vr += vrInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->adjustVolumeRamp(false);
+        }
+
+        // constant gain
+        else {
+            const uint32_t vrl = t->volumeRL;
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                out[0] = mulAddRL(1, rl, vrl, out[0]);
+                out[1] = mulAddRL(0, rl, vrl, out[1]);
+                out += 2;
+            } while (--frameCount);
+        }
+    }
     t->in = in;
 }
 
-void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
 {
     int16_t const *in = static_cast<int16_t const *>(t->in);
 
-    // ramp gain
-    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
-        int32_t vl = t->prevVolume[0];
-        int32_t vr = t->prevVolume[1];
-        const int32_t vlInc = t->volumeInc[0];
-        const int32_t vrInc = t->volumeInc[1];
+    if UNLIKELY(aux != NULL) {
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            int32_t va = t->prevAuxLevel;
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+            const int32_t vaInc = t->auxInc;
 
-        // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
-        //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
-        //         (vl + vlInc*frameCount)/65536.0f, frameCount);
+            // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //         (vl + vlInc*frameCount)/65536.0f, frameCount);
 
-        do {
-            int32_t l = *in++;
-            *out++ += (vl >> 16) * l;
-            *out++ += (vr >> 16) * l;
-            vl += vlInc;
-            vr += vrInc;
-        } while (--frameCount);
-       
-        t->prevVolume[0] = vl;
-        t->prevVolume[1] = vr;
-        t->adjustVolumeRamp();
-    }
-    // constant gain
-    else {
-        const int16_t vl = t->volume[0];
-        const int16_t vr = t->volume[1];
-        do {
-            int16_t l = *in++;
-            out[0] = mulAdd(l, vl, out[0]);
-            out[1] = mulAdd(l, vr, out[1]);
-            out += 2;
-        } while (--frameCount);
+            do {
+                int32_t l = *in++;
+                *out++ += (vl >> 16) * l;
+                *out++ += (vr >> 16) * l;
+                *aux++ += (va >> 16) * l;
+                vl += vlInc;
+                vr += vrInc;
+                va += vaInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->prevAuxLevel = va;
+            t->adjustVolumeRamp(true);
+        }
+        // constant gain
+        else {
+            const int16_t vl = t->volume[0];
+            const int16_t vr = t->volume[1];
+            const int16_t va = (int16_t)t->auxLevel;
+            do {
+                int16_t l = *in++;
+                out[0] = mulAdd(l, vl, out[0]);
+                out[1] = mulAdd(l, vr, out[1]);
+                out += 2;
+                aux[0] = mulAdd(l, va, aux[0]);
+                aux++;
+            } while (--frameCount);
+        }
+    } else {
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+
+            // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //         (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+            do {
+                int32_t l = *in++;
+                *out++ += (vl >> 16) * l;
+                *out++ += (vr >> 16) * l;
+                vl += vlInc;
+                vr += vrInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->adjustVolumeRamp(false);
+        }
+        // constant gain
+        else {
+            const int16_t vl = t->volume[0];
+            const int16_t vr = t->volume[1];
+            do {
+                int16_t l = *in++;
+                out[0] = mulAdd(l, vl, out[0]);
+                out[1] = mulAdd(l, vr, out[1]);
+                out += 2;
+            } while (--frameCount);
+        }
     }
     t->in = in;
 }
@@ -624,37 +836,56 @@
 }
 
 // no-op case
-void AudioMixer::process__nop(state_t* state, void* output)
+void AudioMixer::process__nop(state_t* state)
 {
-    // this assumes output 16 bits stereo, no resampling
-    memset(output, 0, state->frameCount*4);
-    uint32_t en = state->enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
-        track_t& t = state->tracks[i];
-        size_t outFrames = state->frameCount;
-        while (outFrames) {
-            t.buffer.frameCount = outFrames;
-            t.bufferProvider->getNextBuffer(&t.buffer);
-            if (!t.buffer.raw) break;
-            outFrames -= t.buffer.frameCount;
-            t.bufferProvider->releaseBuffer(&t.buffer);
+    uint32_t e0 = state->enabledTracks;
+    size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
+    while (e0) {
+        // process by group of tracks with same output buffer to
+        // avoid multiple memset() on same buffer
+        uint32_t e1 = e0, e2 = e0;
+        int i = 31 - __builtin_clz(e1);
+        track_t& t1 = state->tracks[i];
+        e2 &= ~(1<<i);
+        while (e2) {
+            i = 31 - __builtin_clz(e2);
+            e2 &= ~(1<<i);
+            track_t& t2 = state->tracks[i];
+            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
+                e1 &= ~(1<<i);
+            }
+        }
+        e0 &= ~(e1);
+
+        memset(t1.mainBuffer, 0, bufSize);
+
+        while (e1) {
+            i = 31 - __builtin_clz(e1);
+            e1 &= ~(1<<i);
+            t1 = state->tracks[i];
+            size_t outFrames = state->frameCount;
+            while (outFrames) {
+                t1.buffer.frameCount = outFrames;
+                t1.bufferProvider->getNextBuffer(&t1.buffer);
+                if (!t1.buffer.raw) break;
+                outFrames -= t1.buffer.frameCount;
+                t1.bufferProvider->releaseBuffer(&t1.buffer);
+            }
         }
     }
 }
 
 // generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+void AudioMixer::process__genericNoResampling(state_t* state)
 {
     int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
 
     // acquire each track's buffer
     uint32_t enabledTracks = state->enabledTracks;
-    uint32_t en = enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
+    uint32_t e0 = enabledTracks;
+    while (e0) {
+        const int i = 31 - __builtin_clz(e0);
+        e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.buffer.frameCount = state->frameCount;
         t.bufferProvider->getNextBuffer(&t.buffer);
@@ -666,110 +897,156 @@
             enabledTracks &= ~(1<<i);
     }
 
-    // this assumes output 16 bits stereo, no resampling
-    int32_t* out = static_cast<int32_t*>(output);
-    size_t numFrames = state->frameCount;
-    do {
-        memset(outTemp, 0, sizeof(outTemp));
-
-        en = enabledTracks;
-        while (en) {
-            const int i = 31 - __builtin_clz(en);
-            en &= ~(1<<i);
-            track_t& t = state->tracks[i];
-            size_t outFrames = BLOCKSIZE;
-           
-            while (outFrames) {
-                size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
-                if (inFrames) {
-                    (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
-                    t.frameCount -= inFrames;
-                    outFrames -= inFrames;
-                }
-                if (t.frameCount == 0 && outFrames) {
-                    t.bufferProvider->releaseBuffer(&t.buffer);
-                    t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
-                    t.bufferProvider->getNextBuffer(&t.buffer);
-                    t.in = t.buffer.raw;
-                    if (t.in == NULL) {
-                        enabledTracks &= ~(1<<i);
-                        break;
-                    }
-                    t.frameCount = t.buffer.frameCount;
-                 }
+    e0 = enabledTracks;
+    while (e0) {
+        // process by group of tracks with same output buffer to
+        // optimize cache use
+        uint32_t e1 = e0, e2 = e0;
+        int j = 31 - __builtin_clz(e1);
+        track_t& t1 = state->tracks[j];
+        e2 &= ~(1<<j);
+        while (e2) {
+            j = 31 - __builtin_clz(e2);
+            e2 &= ~(1<<j);
+            track_t& t2 = state->tracks[j];
+            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
+                e1 &= ~(1<<j);
             }
         }
-
-        ditherAndClamp(out, outTemp, BLOCKSIZE);
-        out += BLOCKSIZE;
-        numFrames -= BLOCKSIZE;
-    } while (numFrames);
-
+        e0 &= ~(e1);
+        // this assumes output 16 bits stereo, no resampling
+        int32_t *out = t1.mainBuffer;
+        size_t numFrames = 0;
+        do {
+            memset(outTemp, 0, sizeof(outTemp));
+            e2 = e1;
+            while (e2) {
+                const int i = 31 - __builtin_clz(e2);
+                e2 &= ~(1<<i);
+                track_t& t = state->tracks[i];
+                size_t outFrames = BLOCKSIZE;
+                int32_t *aux = NULL;
+                if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+                    aux = t.auxBuffer + numFrames;
+                }
+                while (outFrames) {
+                    size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
+                    if (inFrames) {
+                        (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
+                        t.frameCount -= inFrames;
+                        outFrames -= inFrames;
+                        if UNLIKELY(aux != NULL) {
+                            aux += inFrames;
+                        }
+                    }
+                    if (t.frameCount == 0 && outFrames) {
+                        t.bufferProvider->releaseBuffer(&t.buffer);
+                        t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
+                        t.bufferProvider->getNextBuffer(&t.buffer);
+                        t.in = t.buffer.raw;
+                        if (t.in == NULL) {
+                            enabledTracks &= ~(1<<i);
+                            e1 &= ~(1<<i);
+                            break;
+                        }
+                        t.frameCount = t.buffer.frameCount;
+                    }
+                }
+            }
+            ditherAndClamp(out, outTemp, BLOCKSIZE);
+            out += BLOCKSIZE;
+            numFrames += BLOCKSIZE;
+        } while (numFrames < state->frameCount);
+    }
 
     // release each track's buffer
-    en = enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
+    e0 = enabledTracks;
+    while (e0) {
+        const int i = 31 - __builtin_clz(e0);
+        e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.bufferProvider->releaseBuffer(&t.buffer);
     }
 }
 
-// generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state, void* output)
+
+  // generic code with resampling
+void AudioMixer::process__genericResampling(state_t* state)
 {
     int32_t* const outTemp = state->outputTemp;
     const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
     memset(outTemp, 0, size);
 
-    int32_t* out = static_cast<int32_t*>(output);
     size_t numFrames = state->frameCount;
 
-    uint32_t en = state->enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
-        track_t& t = state->tracks[i];
-
-        // this is a little goofy, on the resampling case we don't
-        // acquire/release the buffers because it's done by
-        // the resampler.
-        if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
-            (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
-        } else {
-
-            size_t outFrames = numFrames;
-           
-            while (outFrames) {
-                t.buffer.frameCount = outFrames;
-                t.bufferProvider->getNextBuffer(&t.buffer);
-                t.in = t.buffer.raw;
-                // t.in == NULL can happen if the track was flushed just after having
-                // been enabled for mixing.
-                if (t.in == NULL) break;
-
-                (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
-                outFrames -= t.buffer.frameCount;
-                t.bufferProvider->releaseBuffer(&t.buffer);
+    uint32_t e0 = state->enabledTracks;
+    while (e0) {
+        // process by group of tracks with same output buffer
+        // to optimize cache use
+        uint32_t e1 = e0, e2 = e0;
+        int j = 31 - __builtin_clz(e1);
+        track_t& t1 = state->tracks[j];
+        e2 &= ~(1<<j);
+        while (e2) {
+            j = 31 - __builtin_clz(e2);
+            e2 &= ~(1<<j);
+            track_t& t2 = state->tracks[j];
+            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
+                e1 &= ~(1<<j);
             }
         }
-    }
+        e0 &= ~(e1);
+        int32_t *out = t1.mainBuffer;
+        while (e1) {
+            const int i = 31 - __builtin_clz(e1);
+            e1 &= ~(1<<i);
+            track_t& t = state->tracks[i];
+            int32_t *aux = NULL;
+            if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+                aux = t.auxBuffer;
+            }
 
-    ditherAndClamp(out, outTemp, numFrames);
+            // this is a little goofy, on the resampling case we don't
+            // acquire/release the buffers because it's done by
+            // the resampler.
+            if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+                (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
+            } else {
+
+                size_t outFrames = 0;
+
+                while (outFrames < numFrames) {
+                    t.buffer.frameCount = numFrames - outFrames;
+                    t.bufferProvider->getNextBuffer(&t.buffer);
+                    t.in = t.buffer.raw;
+                    // t.in == NULL can happen if the track was flushed just after having
+                    // been enabled for mixing.
+                    if (t.in == NULL) break;
+
+                    if UNLIKELY(aux != NULL) {
+                        aux += outFrames;
+                    }
+                    (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
+                    outFrames += t.buffer.frameCount;
+                    t.bufferProvider->releaseBuffer(&t.buffer);
+                }
+            }
+        }
+        ditherAndClamp(out, outTemp, numFrames);
+    }
 }
 
 // one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
 {
     const int i = 31 - __builtin_clz(state->enabledTracks);
     const track_t& t = state->tracks[i];
 
     AudioBufferProvider::Buffer& b(t.buffer);
-   
-    int32_t* out = static_cast<int32_t*>(output);
+
+    int32_t* out = t.mainBuffer;
     size_t numFrames = state->frameCount;
-  
+
     const int16_t vl = t.volume[0];
     const int16_t vr = t.volume[1];
     const uint32_t vrl = t.volumeRL;
@@ -787,7 +1064,7 @@
             return;
         }
         size_t outFrames = b.frameCount;
-       
+
         if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
             // volume is boosted, so we might need to clamp even though
             // we process only one track.
@@ -816,7 +1093,9 @@
 }
 
 // 2 tracks is also a common case
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
+// NEVER used in current implementation of process__validate()
+// only use if the 2 tracks have the same output buffer
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
 {
     int i;
     uint32_t en = state->enabledTracks;
@@ -829,24 +1108,25 @@
     i = 31 - __builtin_clz(en);
     const track_t& t1 = state->tracks[i];
     AudioBufferProvider::Buffer& b1(t1.buffer);
-   
+
     int16_t const *in0;
     const int16_t vl0 = t0.volume[0];
     const int16_t vr0 = t0.volume[1];
     size_t frameCount0 = 0;
-  
+
     int16_t const *in1;
     const int16_t vl1 = t1.volume[0];
     const int16_t vr1 = t1.volume[1];
     size_t frameCount1 = 0;
-   
-    int32_t* out = static_cast<int32_t*>(output);
+
+    //FIXME: only works if two tracks use same buffer
+    int32_t* out = t0.mainBuffer;
     size_t numFrames = state->frameCount;
     int16_t const *buff = NULL;
 
-  
+
     while (numFrames) {
-   
+
         if (frameCount0 == 0) {
             b0.frameCount = numFrames;
             t0.bufferProvider->getNextBuffer(&b0);
@@ -875,13 +1155,13 @@
             }
             frameCount1 = b1.frameCount;
         }
-       
+
         size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
 
         numFrames -= outFrames;
         frameCount0 -= outFrames;
         frameCount1 -= outFrames;
-       
+
         do {
             int32_t l0 = *in0++;
             int32_t r0 = *in0++;
@@ -896,17 +1176,17 @@
             r = clamp16(r);
             *out++ = (r<<16) | (l & 0xFFFF);
         } while (--outFrames);
-       
+
         if (frameCount0 == 0) {
             t0.bufferProvider->releaseBuffer(&b0);
         }
         if (frameCount1 == 0) {
             t1.bufferProvider->releaseBuffer(&b1);
         }
-    }   
-       
+    }
+
     if (buff != NULL) {
-        delete [] buff;       
+        delete [] buff;
     }
 }
 
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 15766cd..aee3e17 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -63,11 +63,14 @@
         // for target TRACK
         CHANNEL_COUNT   = 0x4000,
         FORMAT          = 0x4001,
+        MAIN_BUFFER     = 0x4002,
+        AUX_BUFFER      = 0x4003,
         // for TARGET RESAMPLE
         SAMPLE_RATE     = 0x4100,
         // for TARGET VOLUME (8 channels max)
         VOLUME0         = 0x4200,
         VOLUME1         = 0x4201,
+        AUXLEVEL        = 0x4210,
     };
 
 
@@ -78,10 +81,10 @@
     status_t    disable(int name);
 
     status_t    setActiveTrack(int track);
-    status_t    setParameter(int target, int name, int value);
+    status_t    setParameter(int target, int name, void *value);
 
     status_t    setBufferProvider(AudioBufferProvider* bufferProvider);
-    void        process(void* output);
+    void        process();
 
     uint32_t    trackNames() const { return mTrackNames; }
 
@@ -94,6 +97,7 @@
         NEEDS_FORMAT__MASK          = 0x000000F0,
         NEEDS_MUTE__MASK            = 0x00000100,
         NEEDS_RESAMPLE__MASK        = 0x00001000,
+        NEEDS_AUX__MASK             = 0x00010000,
     };
 
     enum {
@@ -107,6 +111,9 @@
 
         NEEDS_RESAMPLE_DISABLED     = 0x00000000,
         NEEDS_RESAMPLE_ENABLED      = 0x00001000,
+
+        NEEDS_AUX_DISABLED     = 0x00000000,
+        NEEDS_AUX_ENABLED      = 0x00010000,
     };
 
     static inline int32_t applyVolume(int32_t in, int32_t v) {
@@ -115,9 +122,10 @@
 
 
     struct state_t;
+    struct track_t;
 
-    typedef void (*mix_t)(state_t* state, void* output);
-
+    typedef void (*mix_t)(state_t* state);
+    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
     static const int BLOCKSIZE = 16; // 4 cache lines
 
     struct track_t {
@@ -131,6 +139,9 @@
         int32_t     prevVolume[2];
 
         int32_t     volumeInc[2];
+        int32_t     auxLevel;
+        int32_t     auxInc;
+        int32_t     prevAuxLevel;
 
         uint16_t    frameCount;
 
@@ -142,15 +153,17 @@
         AudioBufferProvider*                bufferProvider;
         mutable AudioBufferProvider::Buffer buffer;
 
-        void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+        hook_t      hook;
         void const* in;             // current location in buffer
 
         AudioResampler*     resampler;
         uint32_t            sampleRate;
+        int32_t*           mainBuffer;
+        int32_t*           auxBuffer;
 
         bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
         bool        doesResample() const;
-        void        adjustVolumeRamp();
+        void        adjustVolumeRamp(bool aux);
     };
 
     // pad to 32-bytes to fill cache line
@@ -173,18 +186,19 @@
 
     void invalidateState(uint32_t mask);
 
-    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
-    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
+    static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
 
-    static void process__validate(state_t* state, void* output);
-    static void process__nop(state_t* state, void* output);
-    static void process__genericNoResampling(state_t* state, void* output);
-    static void process__genericResampling(state_t* state, void* output);
-    static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
-    static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+    static void process__validate(state_t* state);
+    static void process__nop(state_t* state);
+    static void process__genericNoResampling(state_t* state);
+    static void process__genericResampling(state_t* state);
+    static void process__OneTrack16BitsStereoNoResampling(state_t* state);
+    static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index e4d5bb3..1415493 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -71,6 +71,8 @@
 const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
 const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
 const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
+const char CameraParameters::KEY_METERING_MODE[] = "metering-mode";
+const char CameraParameters::KEY_SUPPORTED_METERING_MODES[] = "metering-mode-values";
 
 const char CameraParameters::TRUE[] = "true";
 const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
@@ -142,6 +144,11 @@
 const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
 const char CameraParameters::FOCUS_MODE_CONTINUOUS[] = "continuous";
 
+// Values for metering mode settings.
+const char CameraParameters::METERING_MODE_CENTER_WEIGHTED[] = "center-weighted";
+const char CameraParameters::METERING_MODE_FRAME_AVERAGE[] = "frame-average";
+const char CameraParameters::METERING_MODE_SPOT[] = "spot";
+
 CameraParameters::CameraParameters()
                 : mMap()
 {
diff --git a/libs/rs/java/Fountain/res/raw/fountain.rs b/libs/rs/java/Fountain/res/raw/fountain.rs
index 67f7ef5..fe2ca33d 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.rs
+++ b/libs/rs/java/Fountain/res/raw/fountain.rs
@@ -40,6 +40,18 @@
     return 1;
 }
 
+// Putting the overloadable attribute on this function breaks rendering
+// appears to be a bug.
+static uchar4 /*__attribute__((overloadable))*/ pack(float r, float g, float b)
+{
+    uchar4 c;
+    c.x = (uchar)(r * 255.f);
+    c.y = (uchar)(g * 255.f);
+    c.z = (uchar)(b * 255.f);
+    c.w = 255;
+    return c;
+}
+
 void addParticles(int rate, int x, int y)
 {
     //rsDebug("partColor", partColor);
@@ -51,7 +63,10 @@
     float rMax = ((float)rate) * 0.005f;
     int size = rsAllocationGetDimX(rsGetAllocation(point));
 
-    uchar4 c = rsPackColorTo8888(partColor.x, partColor.y, partColor.z);
+    //uchar4 c = rsPackColorTo8888(partColor.x, partColor.y, partColor.z);
+    uchar4 c = pack(partColor.x, partColor.y, partColor.z);
+    c.x = 255;
+    c.w = 255;
 
     //rsDebug("color ", ((int *)&c)[0]);
     Point_t * np = &point[newPart];
diff --git a/libs/rs/java/Fountain/res/raw/fountain_bc.bc b/libs/rs/java/Fountain/res/raw/fountain_bc.bc
index 7b2e88b..d223460 100644
--- a/libs/rs/java/Fountain/res/raw/fountain_bc.bc
+++ b/libs/rs/java/Fountain/res/raw/fountain_bc.bc
Binary files differ
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point.java b/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point.java
index b091f39..91db2c6 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point.java
@@ -30,9 +30,9 @@
         mItemArray = new Item[count];
 
         Element.Builder eb = new Element.Builder(rs);
-        eb.add(Element.createVector(rs, Element.DataType.FLOAT_32, 2), "delta");
-        eb.add(Element.createAttrib(rs, Element.DataType.FLOAT_32, Element.DataKind.POSITION, 2), "position");
-        eb.add(Element.createAttrib(rs, Element.DataType.UNSIGNED_8, Element.DataKind.COLOR, 4), "color");
+        eb.add(Element.F32_2(rs), "delta");
+        eb.add(Element.F32_2(rs), "position");
+        eb.add(Element.U8_4(rs), "color");
         mElement = eb.create();
 
         init(rs, count);
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index d4c29c8..d667c86 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -178,11 +178,11 @@
         }
         mShader.append(mUserShader);
     } else {
-        mShader.append("attribute vec4 ATTRIB_LegacyPosition;\n");
-        mShader.append("attribute vec4 ATTRIB_LegacyColor;\n");
-        mShader.append("attribute vec3 ATTRIB_LegacyNormal;\n");
-        mShader.append("attribute float ATTRIB_LegacyPointSize;\n");
-        mShader.append("attribute vec4 ATTRIB_LegacyTexture;\n");
+        mShader.append("attribute vec4 ATTRIB_position;\n");
+        mShader.append("attribute vec4 ATTRIB_color;\n");
+        mShader.append("attribute vec3 ATTRIB_normal;\n");
+        mShader.append("attribute float ATTRIB_pointSize;\n");
+        mShader.append("attribute vec4 ATTRIB_texture0;\n");
 
         for (uint32_t ct=0; ct < mUniformCount; ct++) {
             mShader.append("uniform mat4 ");
@@ -191,14 +191,14 @@
         }
 
         mShader.append("void main() {\n");
-        mShader.append("  gl_Position = UNI_MVP * ATTRIB_LegacyPosition;\n");
-        mShader.append("  gl_PointSize = ATTRIB_LegacyPointSize;\n");
+        mShader.append("  gl_Position = UNI_MVP * ATTRIB_position;\n");
+        mShader.append("  gl_PointSize = ATTRIB_pointSize;\n");
 
-        mShader.append("  varColor = ATTRIB_LegacyColor;\n");
+        mShader.append("  varColor = ATTRIB_color;\n");
         if (mTextureMatrixEnable) {
-            mShader.append("  varTex0 = UNI_TexMatrix * ATTRIB_LegacyTexture;\n");
+            mShader.append("  varTex0 = UNI_TexMatrix * ATTRIB_texture0;\n");
         } else {
-            mShader.append("  varTex0 = ATTRIB_LegacyTexture;\n");
+            mShader.append("  varTex0 = ATTRIB_texture0;\n");
         }
         //mShader.append("  pos.x = pos.x / 480.0;\n");
         //mShader.append("  pos.y = pos.y / 800.0;\n");
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 18f873e..8f650f8 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -131,12 +131,8 @@
 
     float vtx[] = { x1, y1, z1, x2, y2, z2 };
     VertexArray va;
-    va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
-    if (rsc->checkVersion2_0()) {
-        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-    } else {
-        va.setupGL(rsc, &rsc->mStateVertexArray);
-    }
+    va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "position");
+    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
 
     glDrawArrays(GL_LINES, 0, 2);
 }
@@ -151,12 +147,8 @@
     float vtx[] = { x, y, z };
 
     VertexArray va;
-    va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
-    if (rsc->checkVersion2_0()) {
-        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-    } else {
-        va.setupGL(rsc, &rsc->mStateVertexArray);
-    }
+    va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "position");
+    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
 
     glDrawArrays(GL_POINTS, 0, 1);
 }
@@ -185,14 +177,9 @@
     const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
 
     VertexArray va;
-    va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
-    va.addLegacy(GL_FLOAT, 2, 8, RS_KIND_TEXTURE, false, (uint32_t)tex);
-    if (rsc->checkVersion2_0()) {
-        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-    } else {
-        va.setupGL(rsc, &rsc->mStateVertexArray);
-    }
-
+    va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "position");
+    va.add(GL_FLOAT, 2, 8, false, (uint32_t)tex, "texture0");
+    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
 
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 0218dc5..504ffba 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -98,16 +98,11 @@
         glAttachShader(pgm, frag->getShaderID());
 
         if (!vtx->isUserProgram()) {
-            glBindAttribLocation(pgm, 0, "ATTRIB_LegacyPosition");
-            glBindAttribLocation(pgm, 1, "ATTRIB_LegacyColor");
-            glBindAttribLocation(pgm, 2, "ATTRIB_LegacyNormal");
-            glBindAttribLocation(pgm, 3, "ATTRIB_LegacyPointSize");
-            glBindAttribLocation(pgm, 4, "ATTRIB_LegacyTexture");
-            e->mVtxAttribSlots[RS_KIND_POSITION] = 0;
-            e->mVtxAttribSlots[RS_KIND_COLOR] = 1;
-            e->mVtxAttribSlots[RS_KIND_NORMAL] = 2;
-            e->mVtxAttribSlots[RS_KIND_POINT_SIZE] = 3;
-            e->mVtxAttribSlots[RS_KIND_TEXTURE] = 4;
+            glBindAttribLocation(pgm, 0, "ATTRIB_position");
+            glBindAttribLocation(pgm, 1, "ATTRIB_color");
+            glBindAttribLocation(pgm, 2, "ATTRIB_normal");
+            glBindAttribLocation(pgm, 3, "ATTRIB_pointSize");
+            glBindAttribLocation(pgm, 4, "ATTRIB_texture0");
         }
 
         //LOGE("e2 %x", glGetError());
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
index 170b792..2dd082d 100644
--- a/libs/rs/rsSimpleMesh.cpp
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -68,21 +68,12 @@
 
     rsc->checkError("SimpleMesh::renderRange 1");
     VertexArray va;
-    if (rsc->checkVersion2_0()) {
-        for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
-            mVertexBuffers[ct]->uploadCheck(rsc);
-            va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
-            mVertexTypes[ct]->enableGLVertexBuffer2(&va);
-        }
-        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-    } else {
-        for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
-            mVertexBuffers[ct]->uploadCheck(rsc);
-            va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
-            mVertexTypes[ct]->enableGLVertexBuffer(&va);
-        }
-        va.setupGL(rsc, 0);
+    for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+        mVertexBuffers[ct]->uploadCheck(rsc);
+        va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+        mVertexTypes[ct]->enableGLVertexBuffer(&va);
     }
+    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
 
     rsc->checkError("SimpleMesh::renderRange 2");
     if (mIndexType.get()) {
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 8f99209..89e73b0 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -148,131 +148,22 @@
     for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
         const Component &c = getElement()->getField(ct)->getComponent();
 
-        switch(c.getKind()) {
-        case RS_KIND_USER:
-            mGL.mUser[userNum].size = c.getVectorSize();
-            mGL.mUser[userNum].offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mUser[userNum].type = c.getGLType();
-            mGL.mUser[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
-            mGL.mUser[userNum].name.setTo(getElement()->getFieldName(ct));
-            userNum ++;
-            break;
-
-        case RS_KIND_POSITION:
-            rsAssert(mGL.mVtx.size == 0);
-            mGL.mVtx.size = c.getVectorSize();
-            mGL.mVtx.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mVtx.type = c.getGLType();
-            mGL.mVtx.normalized = false;
-            mGL.mVtx.name.setTo("Position");
-            break;
-
-        case RS_KIND_COLOR:
-            rsAssert(mGL.mColor.size == 0);
-            mGL.mColor.size = c.getVectorSize();
-            mGL.mColor.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mColor.type = c.getGLType();
-            mGL.mColor.normalized = c.getType() != RS_TYPE_FLOAT_32;
-            mGL.mColor.name.setTo("Color");
-            break;
-
-        case RS_KIND_NORMAL:
-            rsAssert(mGL.mNorm.size == 0);
-            mGL.mNorm.size = c.getVectorSize();
-            mGL.mNorm.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mNorm.type = c.getGLType();
-            mGL.mNorm.normalized = false;
-            mGL.mNorm.name.setTo("Normal");
-            break;
-
-        case RS_KIND_TEXTURE:
-            rsAssert(mGL.mTex.size == 0);
-            mGL.mTex.size = c.getVectorSize();
-            mGL.mTex.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mTex.type = c.getGLType();
-            mGL.mTex.normalized = false;
-            mGL.mTex.name.setTo("Texture");
-            break;
-
-        case RS_KIND_POINT_SIZE:
-            rsAssert(!mGL.mPointSize.size);
-            mGL.mPointSize.size = c.getVectorSize();
-            mGL.mPointSize.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mPointSize.type = c.getGLType();
-            mGL.mPointSize.normalized = false;
-            mGL.mPointSize.name.setTo("PointSize");
-        break;
-
-        default:
-            break;
-        }
+        mAttribs[userNum].size = c.getVectorSize();
+        mAttribs[userNum].offset = mElement->getFieldOffsetBytes(ct);
+        mAttribs[userNum].type = c.getGLType();
+        mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+        mAttribs[userNum].name.setTo(getElement()->getFieldName(ct));
+        userNum ++;
     }
 }
 
+
 void Type::enableGLVertexBuffer(VertexArray *va) const
 {
-    // Note: We are only going to enable buffers and never disable them
-    // here.  The reason is more than one Allocation may be used as a vertex
-    // source.  So we cannot disable arrays that may have been in use by
-    // another allocation.
-
-    uint32_t stride = mElement->getSizeBytes();
-    if (mGL.mVtx.size) {
-        va->addLegacy(mGL.mVtx.type,
-                      mGL.mVtx.size,
-                      stride,
-                      RS_KIND_POSITION,
-                      false,
-                      mGL.mVtx.offset);
-    }
-
-    if (mGL.mNorm.size) {
-        va->addLegacy(mGL.mNorm.type,
-                     3,
-                     stride,
-                     RS_KIND_NORMAL,
-                     false,
-                     mGL.mNorm.offset);
-    }
-
-    if (mGL.mColor.size) {
-        va->addLegacy(mGL.mColor.type,
-                     mGL.mColor.size,
-                     stride,
-                     RS_KIND_COLOR,
-                     true,
-                     mGL.mColor.offset);
-    }
-
-    if (mGL.mTex.size) {
-        va->addLegacy(mGL.mTex.type,
-                     mGL.mTex.size,
-                     stride,
-                     RS_KIND_TEXTURE,
-                     false,
-                     mGL.mTex.offset);
-    }
-
-    if (mGL.mPointSize.size) {
-        va->addLegacy(mGL.mPointSize.type,
-                     1,
-                     stride,
-                     RS_KIND_POINT_SIZE,
-                     false,
-                     mGL.mPointSize.offset);
-    }
-
-}
-
-void Type::enableGLVertexBuffer2(VertexArray *va) const
-{
-    // Do legacy buffers
-    enableGLVertexBuffer(va);
-
     uint32_t stride = mElement->getSizeBytes();
     for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
-        if (mGL.mUser[ct].size) {
-            va->addUser(mGL.mUser[ct], stride);
+        if (mAttribs[ct].size) {
+            va->add(mAttribs[ct], stride);
         }
     }
 }
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 664f343..f598f64 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -71,7 +71,6 @@
     void compute();
 
     void enableGLVertexBuffer(class VertexArray *) const;
-    void enableGLVertexBuffer2(class VertexArray *) const;
 
     void dumpLOGV(const char *prefix) const;
     virtual void serialize(OStream *stream) const;
@@ -115,15 +114,7 @@
     LOD *mLODs;
     uint32_t mLODCount;
 
-    struct GLState_t {
-        VertexArray::Attrib mUser[RS_MAX_ATTRIBS];
-        VertexArray::Attrib mVtx;
-        VertexArray::Attrib mNorm;
-        VertexArray::Attrib mColor;
-        VertexArray::Attrib mTex;
-        VertexArray::Attrib mPointSize;
-    };
-    GLState_t mGL;
+    VertexArray::Attrib mAttribs[RS_MAX_ATTRIBS];
     void makeGLComponents();
 
 private:
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp
index b42d1c4..6f15db075 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/rsVertexArray.cpp
@@ -60,7 +60,6 @@
     size = a.size;
     stride = a.stride;
     normalized = a.normalized;
-    kind = RS_KIND_USER;
     name.setTo(a.name);
 }
 
@@ -80,17 +79,16 @@
     mAttribs[n].clear();
 }
 
-void VertexArray::addUser(const Attrib &a, uint32_t stride)
+void VertexArray::add(const Attrib &a, uint32_t stride)
 {
     rsAssert(mCount < RS_MAX_ATTRIBS);
     mAttribs[mCount].set(a);
     mAttribs[mCount].buffer = mActiveBuffer;
     mAttribs[mCount].stride = stride;
-    mAttribs[mCount].kind = RS_KIND_USER;
     mCount ++;
 }
 
-void VertexArray::addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset)
+void VertexArray::add(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name)
 {
     rsAssert(mCount < RS_MAX_ATTRIBS);
     mAttribs[mCount].clear();
@@ -100,96 +98,25 @@
     mAttribs[mCount].normalized = normalized;
     mAttribs[mCount].buffer = mActiveBuffer;
     mAttribs[mCount].stride = stride;
-    mAttribs[mCount].kind = kind;
+    mAttribs[mCount].name.setTo(name);
     mCount ++;
 }
 
 void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
-    LOGE("va %i: slot=%i name=%s buf=%i  size=%i  type=0x%x  kind=%i  stride=0x%x  norm=%i  offset=0x%x", idx, slot,
+    LOGE("va %i: slot=%i name=%s buf=%i  size=%i  type=0x%x  stride=0x%x  norm=%i  offset=0x%x", idx, slot,
          mAttribs[idx].name.string(),
          mAttribs[idx].buffer,
          mAttribs[idx].size,
          mAttribs[idx].type,
-         mAttribs[idx].kind,
          mAttribs[idx].stride,
          mAttribs[idx].normalized,
          mAttribs[idx].offset);
 }
 
-void VertexArray::setupGL(const Context *rsc, class VertexArrayState *state) const
-{
-    glClientActiveTexture(GL_TEXTURE0);
-    glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-#ifndef ANDROID_RS_BUILD_FOR_HOST // GLES only
-    glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
-#endif //ANDROID_RS_BUILD_FOR_HOST
-
-    for (uint32_t ct=0; ct < mCount; ct++) {
-        switch(mAttribs[ct].kind) {
-        case RS_KIND_POSITION:
-            //logAttrib(POSITION);
-            glEnableClientState(GL_VERTEX_ARRAY);
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-            glVertexPointer(mAttribs[ct].size,
-                            mAttribs[ct].type,
-                            mAttribs[ct].stride,
-                            (void *)mAttribs[ct].offset);
-            break;
-
-        case RS_KIND_NORMAL:
-            //logAttrib(NORMAL);
-            glEnableClientState(GL_NORMAL_ARRAY);
-            rsAssert(mAttribs[ct].size == 3);
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-            glNormalPointer(mAttribs[ct].type,
-                            mAttribs[ct].stride,
-                            (void *)mAttribs[ct].offset);
-            break;
-
-        case RS_KIND_COLOR:
-            //logAttrib(COLOR);
-            glEnableClientState(GL_COLOR_ARRAY);
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-            glColorPointer(mAttribs[ct].size,
-                           mAttribs[ct].type,
-                           mAttribs[ct].stride,
-                           (void *)mAttribs[ct].offset);
-            break;
-
-        case RS_KIND_TEXTURE:
-            //logAttrib(TEXTURE);
-            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-            glTexCoordPointer(mAttribs[ct].size,
-                              mAttribs[ct].type,
-                              mAttribs[ct].stride,
-                              (void *)mAttribs[ct].offset);
-            break;
-#ifndef ANDROID_RS_BUILD_FOR_HOST // GLES only
-        case RS_KIND_POINT_SIZE:
-            //logAttrib(POINT_SIZE);
-            glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-            glPointSizePointerOES(mAttribs[ct].type,
-                                  mAttribs[ct].stride,
-                                  (void *)mAttribs[ct].offset);
-            break;
-#endif //ANDROID_RS_BUILD_FOR_HOST
-
-        default:
-            rsAssert(0);
-        }
-    }
-
-    rsc->checkError("VertexArray::setupGL");
-}
-
 void VertexArray::setupGL2(const Context *rsc, class VertexArrayState *state, ShaderCache *sc) const
 {
     rsc->checkError("VertexArray::setupGL2 start");
-    for (uint32_t ct=1; ct <= state->mLastEnableCount; ct++) {
+    for (uint32_t ct=1; ct <= 0xf/*state->mLastEnableCount*/; ct++) {
         glDisableVertexAttribArray(ct);
     }
 
@@ -199,16 +126,24 @@
         if (sc->isUserVertexProgram()) {
             slot = sc->vtxAttribSlot(ct);
         } else {
-            if (mAttribs[ct].kind == RS_KIND_USER) {
+            if (mAttribs[ct].name == "position") {
+                slot = 0;
+            } else if (mAttribs[ct].name == "color") {
+                slot = 1;
+            } else if (mAttribs[ct].name == "normal") {
+                slot = 2;
+            } else if (mAttribs[ct].name == "pointSize") {
+                slot = 3;
+            } else if (mAttribs[ct].name == "texture0") {
+                slot = 4;
+            } else {
                 continue;
             }
-            slot = sc->vtxAttribSlot(mAttribs[ct].kind);
         }
 
         //logAttrib(ct, slot);
         glEnableVertexAttribArray(slot);
         glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-
         glVertexAttribPointer(slot,
                               mAttribs[ct].size,
                               mAttribs[ct].type,
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/rsVertexArray.h
index 3904cb6..e5b51d7 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/rsVertexArray.h
@@ -43,7 +43,6 @@
         uint32_t stride;
         bool normalized;
         String8 name;
-        RsDataKind kind;
 
         Attrib();
         void set(const Attrib &);
@@ -53,8 +52,9 @@
 
     void clearAll();
     void setActiveBuffer(uint32_t id) {mActiveBuffer = id;}
-    void addUser(const Attrib &, uint32_t stride);
-    void addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset);
+    void add(const Attrib &, uint32_t stride);
+    //void addLegacy(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset);
+    void add(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name);
 
     void setupGL(const Context *rsc, class VertexArrayState *) const;
     void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
new file mode 100644
index 0000000..c0ba4af
--- /dev/null
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -0,0 +1,61 @@
+#ifndef __RS_CORE_RSH__
+#define __RS_CORE_RSH__
+
+//uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b);
+//uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a);
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
+{
+    uchar4 c;
+    c.x = (uchar)(r * 255.f);
+    c.y = (uchar)(g * 255.f);
+    c.z = (uchar)(b * 255.f);
+    c.w = 255;
+    return c;
+}
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
+{
+    uchar4 c;
+    c.x = (uchar)(r * 255.f);
+    c.y = (uchar)(g * 255.f);
+    c.z = (uchar)(b * 255.f);
+    c.w = (uchar)(a * 255.f);
+    return c;
+}
+
+
+/*
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
+{
+    color *= 255.f;
+    uchar4 c = {color.x, color.y, color.z, 255};
+    return c;
+}
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
+{
+    color *= 255.f;
+    uchar4 c = {color.x, color.y, color.z, color.w};
+    return c;
+}
+
+static float4 rsUnpackColor8888(uchar4 c)
+{
+    float4 ret = {
+        c.x * (1.f / 255.f),
+        c.y * (1.f / 255.f),
+        c.z * (1.f / 255.f),
+        c.w * (1.f / 255.f),
+    };
+    return ret;
+}
+
+extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float r, float g, float b);
+extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float3);
+extern float4 rsUnpackColor565(uchar4);
+*/
+
+
+#endif
+
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index 91c4303..a26491f 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -1,4 +1,6 @@
 #include "rs_cl.rsh"
+#include "rs_core.rsh"
+
 
 
 // Allocations
@@ -11,18 +13,6 @@
 
 
 
-// Color conversion
-extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b);
-extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a);
-extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3);
-extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4);
-extern float4 rsUnpackColor8888(uchar4);
-
-extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float r, float g, float b);
-extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float3);
-extern float4 rsUnpackColor565(uchar4);
-
-
 // Debugging
 extern void __attribute__((overloadable))rsDebug(const char *, float);
 extern void __attribute__((overloadable))rsDebug(const char *, float2);
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 185bb83..2ac81e5 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -68,32 +68,6 @@
 typedef int int16 __attribute__((ext_vector_type(16)));
 
 
-// RS_KIND_POSITION
-typedef float rs_position1;
-typedef float2 rs_position2;
-typedef float3 rs_position3;
-typedef float4 rs_position4;
-
-// RS_KIND_COLOR
-typedef float3 rs_color3f;
-typedef float4 rs_color4f;
-typedef uchar4 rs_color4u;
-
-// RS_KIND_NORMAL
-typedef float3 rs_normal;
-
-// RS_KIND_POINT_SIZE
-typedef float rs_point_size;
-
-// RS_KIND_TEXTURE
-typedef float rs_texture_coord1;
-typedef float2 rs_texture_coord2;
-typedef float3 rs_texture_coord3;
-typedef float4 rs_texture_coord4;
-
-// RS_KIND_INDEX
-typedef ushort rs_index;
-
 typedef struct {
     float m[16];
 } rs_matrix4x4;
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 76733a9..7ab74b4 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -379,33 +379,21 @@
     
     glEnable(GL_TEXTURE_2D);
 
+    GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
     if (UNLIKELY(s.alpha < 0xFF)) {
-        // We have an alpha-modulation. We need to modulate all
-        // texture components by alpha because we're always using 
-        // premultiplied alpha.
-        
-        // If the texture doesn't have an alpha channel we can
-        // use REPLACE and switch to non premultiplied alpha
-        // blending (SRCA/ONE_MINUS_SRCA).
-        
-        GLenum env, src;
-        if (needsBlending()) {
-            env = GL_MODULATE;
-            src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
-        } else {
-            env = GL_REPLACE;
-            src = GL_SRC_ALPHA;
-        }
         const GLfloat alpha = s.alpha * (1.0f/255.0f);
-        glColor4f(alpha, alpha, alpha, alpha);
+        if (mPremultipliedAlpha) {
+            glColor4f(alpha, alpha, alpha, alpha);
+        } else {
+            glColor4f(1, 1, 1, alpha);
+        }
         glEnable(GL_BLEND);
         glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
-        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     } else {
-        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
         glColor4f(1, 1, 1, 1);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
         if (needsBlending()) {
-            GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
             glEnable(GL_BLEND);
             glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
         } else {
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index a78424e..2e2f2df 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -29,7 +29,7 @@
 #include <ui/Region.h>
 #include <ui/Overlay.h>
 
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 #include <private/surfaceflinger/SharedBufferStack.h>
 #include <private/surfaceflinger/LayerState.h>
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 5a6893f..fff0853 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -225,7 +225,7 @@
     return mServerHeap;
 }
 
-sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
+sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
 {
     Mutex::Autolock _l(mStateLock);
     uint32_t token = mTokens.acquire();
@@ -1230,7 +1230,7 @@
 }
 
 sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
-        const String8& name, ISurfaceFlingerClient::surface_data_t* params,
+        const String8& name, ISurfaceComposerClient::surface_data_t* params,
         DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
         uint32_t flags)
 {
@@ -1740,7 +1740,7 @@
 }
 
 sp<ISurface> BClient::createSurface(
-        ISurfaceFlingerClient::surface_data_t* params, int pid,
+        ISurfaceComposerClient::surface_data_t* params, int pid,
         const String8& name,
         DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
         uint32_t flags)
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 2558324..d8fe98c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -32,7 +32,7 @@
 
 #include <ui/PixelFormat.h>
 #include <surfaceflinger/ISurfaceComposer.h>
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 
 #include "Barrier.h"
 #include "Layer.h"
@@ -158,7 +158,7 @@
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     // ISurfaceComposer interface
-    virtual sp<ISurfaceFlingerClient>   createConnection();
+    virtual sp<ISurfaceComposerClient>  createConnection();
     virtual sp<IMemoryHeap>             getCblk() const;
     virtual void                        bootFinished();
     virtual void                        openGlobalTransaction();
@@ -189,7 +189,7 @@
     friend class LayerDim;
 
     sp<ISurface> createSurface(ClientID client, int pid, const String8& name,
-            ISurfaceFlingerClient::surface_data_t* params,
+            ISurfaceComposerClient::surface_data_t* params,
             DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
             uint32_t flags);
 
@@ -393,14 +393,14 @@
 
 // ---------------------------------------------------------------------------
 
-class BClient : public BnSurfaceFlingerClient
+class BClient : public BnSurfaceComposerClient
 {
 public:
     BClient(SurfaceFlinger *flinger, ClientID cid,
             const sp<IMemoryHeap>& cblk);
     ~BClient();
 
-    // ISurfaceFlingerClient interface
+    // ISurfaceComposerClient interface
     virtual sp<IMemoryHeap> getControlBlock() const;
 
     virtual sp<ISurface> createSurface(
diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk
index fe85b34..ce3c71a 100644
--- a/libs/surfaceflinger_client/Android.mk
+++ b/libs/surfaceflinger_client/Android.mk
@@ -4,7 +4,7 @@
 LOCAL_SRC_FILES:= \
 	ISurfaceComposer.cpp \
 	ISurface.cpp \
-	ISurfaceFlingerClient.cpp \
+	ISurfaceComposerClient.cpp \
 	LayerState.cpp \
 	SharedBufferStack.cpp \
 	Surface.cpp \
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index b6f4e24..50495c1 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -46,13 +46,13 @@
     {
     }
 
-    virtual sp<ISurfaceFlingerClient> createConnection()
+    virtual sp<ISurfaceComposerClient> createConnection()
     {
         uint32_t n;
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
-        return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
+        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
     virtual sp<IMemoryHeap> getCblk() const
diff --git a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
similarity index 83%
rename from libs/surfaceflinger_client/ISurfaceFlingerClient.cpp
rename to libs/surfaceflinger_client/ISurfaceComposerClient.cpp
index def96d7..67c7df81 100644
--- a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
@@ -30,7 +30,7 @@
 #include <ui/Rect.h>
 
 #include <surfaceflinger/ISurface.h>
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 #include <private/surfaceflinger/LayerState.h>
 
 // ---------------------------------------------------------------------------
@@ -56,18 +56,18 @@
     SET_STATE
 };
 
-class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient>
+class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
 {
 public:
-    BpSurfaceFlingerClient(const sp<IBinder>& impl)
-        : BpInterface<ISurfaceFlingerClient>(impl)
+    BpSurfaceComposerClient(const sp<IBinder>& impl)
+        : BpInterface<ISurfaceComposerClient>(impl)
     {
     }
 
     virtual sp<IMemoryHeap> getControlBlock() const
     {
         Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
         remote()->transact(GET_CBLK, data, &reply);
         return interface_cast<IMemoryHeap>(reply.readStrongBinder());
     }
@@ -82,7 +82,7 @@
                                         uint32_t flags)
     {
         Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeString8(name);
         data.writeInt32(display);
@@ -94,11 +94,11 @@
         params->readFromParcel(reply);
         return interface_cast<ISurface>(reply.readStrongBinder());
     }
-                                    
+
     virtual status_t destroySurface(SurfaceID sid)
     {
         Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
         data.writeInt32(sid);
         remote()->transact(DESTROY_SURFACE, data, &reply);
         return reply.readInt32();
@@ -107,7 +107,7 @@
     virtual status_t setState(int32_t count, const layer_state_t* states)
     {
         Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
         data.writeInt32(count);
         for (int i=0 ; i<count ; i++)
             states[i].write(data);
@@ -116,18 +116,18 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient");
+IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
 
 // ----------------------------------------------------------------------
 
-status_t BnSurfaceFlingerClient::onTransact(
+status_t BnSurfaceComposerClient::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     // codes that don't require permission check
 
     switch(code) {
         case GET_CBLK: {
-            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
             sp<IMemoryHeap> ctl(getControlBlock());
             reply->writeStrongBinder(ctl->asBinder());
             return NO_ERROR;
@@ -135,7 +135,7 @@
     }
 
     // these must be checked
-     
+
      IPCThreadState* ipc = IPCThreadState::self();
      const int pid = ipc->getCallingPid();
      const int uid = ipc->getCallingUid();
@@ -150,10 +150,10 @@
              return PERMISSION_DENIED;
          }
      }
-   
+
      switch(code) {
         case CREATE_SURFACE: {
-            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
             surface_data_t params;
             int32_t pid = data.readInt32();
             String8 name = data.readString8();
@@ -169,12 +169,12 @@
             return NO_ERROR;
         } break;
         case DESTROY_SURFACE: {
-            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
             reply->writeInt32( destroySurface( data.readInt32() ) );
             return NO_ERROR;
         } break;
         case SET_STATE: {
-            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
             int32_t count = data.readInt32();
             layer_state_t* states = new layer_state_t[count];
             for (int i=0 ; i<count ; i++)
@@ -191,7 +191,7 @@
 
 // ----------------------------------------------------------------------
 
-status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
+status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel)
 {
     token    = parcel.readInt32();
     identity = parcel.readInt32();
@@ -201,7 +201,7 @@
     return NO_ERROR;
 }
 
-status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const
+status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const
 {
     parcel->writeInt32(token);
     parcel->writeInt32(identity);
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 2577dc0..8d03145 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -49,10 +49,6 @@
     return surfaces[i].status;
 }
 
-uint32_t SharedClient::getIdentity(size_t token) const {
-    return uint32_t(surfaces[token].identity);
-}
-
 // ----------------------------------------------------------------------------
 
 
@@ -161,6 +157,12 @@
     return stack.status;
 }
 
+int32_t SharedBufferBase::getIdentity() const
+{
+    SharedBufferStack& stack( *mSharedStack );
+    return stack.identity;
+}
+
 size_t SharedBufferBase::getFrontBuffer() const
 {
     SharedBufferStack& stack( *mSharedStack );
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 35a4e8b..ac4b198 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -104,7 +104,7 @@
 SurfaceControl::SurfaceControl(
         const sp<SurfaceComposerClient>& client, 
         const sp<ISurface>& surface,
-        const ISurfaceFlingerClient::surface_data_t& data,
+        const ISurfaceComposerClient::surface_data_t& data,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
     : mClient(client), mSurface(surface),
       mToken(data.token), mIdentity(data.identity),
@@ -278,7 +278,6 @@
 //  Surface
 // ============================================================================
 
-
 Surface::Surface(const sp<SurfaceControl>& surface)
     : mSurface(surface->mSurface),
       mToken(surface->mToken), mIdentity(surface->mIdentity),
@@ -369,7 +368,7 @@
         LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
         return NO_INIT;
     }
-    return NO_ERROR;
+    return cblk->validate(mToken);
 }
 
 bool Surface::isValid() {
@@ -386,9 +385,7 @@
     }
 
     // verify the identity of this surface
-    SharedClient const* cblk = mClient->getSharedClient();
-
-    uint32_t identity = cblk->getIdentity(mToken);
+    uint32_t identity = mSharedBufferClient->getIdentity();
 
     // this is a bit of a (temporary) special case, identity==0 means that
     // no operation are allowed from the client (eg: dequeue/queue), this
@@ -406,7 +403,7 @@
     }
 
     // check the surface didn't become invalid
-    status_t err = cblk->validate(mToken);
+    status_t err = mSharedBufferClient->getStatus();
     if (err != NO_ERROR) {
         LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
                 mToken, mIdentity, err, strerror(-err));
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 8d39c85..0670d20 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -31,7 +31,7 @@
 #include <ui/DisplayInfo.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
-#include <surfaceflinger/ISurfaceFlingerClient.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 
@@ -42,18 +42,14 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class Composer : public Singleton<Composer>
+class ComposerService : public Singleton<ComposerService>
 {
     // these are constants
     sp<ISurfaceComposer> mComposerService;
     sp<IMemoryHeap> mServerCblkMemory;
     surface_flinger_cblk_t volatile* mServerCblk;
 
-    Mutex mLock;
-    SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
-    SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
-
-    Composer() : Singleton<Composer>() {
+    ComposerService() : Singleton<ComposerService>() {
         const String16 name("SurfaceFlinger");
         while (getService(name, &mComposerService) != NO_ERROR) {
             usleep(250000);
@@ -63,6 +59,39 @@
                 mServerCblkMemory->getBase());
     }
 
+    friend class Singleton<ComposerService>;
+
+public:
+    static sp<ISurfaceComposer> getComposerService() {
+        return ComposerService::getInstance().mComposerService;
+    }
+    static surface_flinger_cblk_t const volatile * getControlBlock() {
+        return ComposerService::getInstance().mServerCblk;
+    }
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
+
+
+static inline sp<ISurfaceComposer> getComposerService() {
+    return ComposerService::getComposerService();
+}
+
+static inline surface_flinger_cblk_t const volatile * get_cblk() {
+    return ComposerService::getControlBlock();
+}
+
+// ---------------------------------------------------------------------------
+
+class Composer : public Singleton<Composer>
+{
+    Mutex mLock;
+    SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
+    SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
+
+    Composer() : Singleton<Composer>() {
+    }
+
     void addClientImpl(const sp<SurfaceComposerClient>& client) {
         Mutex::Autolock _l(mLock);
         mActiveConnections.add(client);
@@ -102,7 +131,7 @@
             mOpenTransactions.clear();
         mLock.unlock();
 
-        sp<ISurfaceComposer> sm(mComposerService);
+        sp<ISurfaceComposer> sm(getComposerService());
         sm->openGlobalTransaction();
             const size_t N = clients.size();
             for (size_t i=0; i<N; i++) {
@@ -114,12 +143,6 @@
     friend class Singleton<Composer>;
 
 public:
-    static sp<ISurfaceComposer> getComposerService() {
-        return Composer::getInstance().mComposerService;
-    }
-    static surface_flinger_cblk_t const volatile * getControlBlock() {
-        return Composer::getInstance().mServerCblk;
-    }
     static void addClient(const sp<SurfaceComposerClient>& client) {
         Composer::getInstance().addClientImpl(client);
     }
@@ -136,14 +159,6 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
 
-static inline sp<ISurfaceComposer> getComposerService() {
-    return Composer::getComposerService();
-}
-
-static inline surface_flinger_cblk_t const volatile * get_cblk() {
-    return Composer::getControlBlock();
-}
-
 // ---------------------------------------------------------------------------
 
 static inline int compare_type( const layer_state_t& lhs,
@@ -162,7 +177,7 @@
 {
     sp<ISurfaceComposer> sm(getComposerService());
     if (sm != 0) {
-        sp<ISurfaceFlingerClient> conn = sm->createConnection();
+        sp<ISurfaceComposerClient> conn = sm->createConnection();
         if (conn != 0) {
             mClient = conn;
             Composer::addClient(this);
@@ -199,7 +214,7 @@
 void SurfaceComposerClient::dispose()
 {
     // this can be called more than once.
-    sp<ISurfaceFlingerClient> client;
+    sp<ISurfaceComposerClient> client;
     Mutex::Autolock _lm(mLock);
     if (mClient != 0) {
         Composer::removeClient(this);
@@ -296,7 +311,7 @@
 {
     sp<SurfaceControl> result;
     if (mStatus == NO_ERROR) {
-        ISurfaceFlingerClient::surface_data_t data;
+        ISurfaceComposerClient::surface_data_t data;
         sp<ISurface> surface = mClient->createSurface(&data, pid, name,
                 display, w, h, format, flags);
         if (surface != 0) {
@@ -558,8 +573,8 @@
 }
 void SurfaceClient::init(const sp<IBinder>& conn)
 {
-    mSignalServer = getComposerService();
-    sp<ISurfaceFlingerClient> sf(interface_cast<ISurfaceFlingerClient>(conn));
+    mComposerService = getComposerService();
+    sp<ISurfaceComposerClient> sf(interface_cast<ISurfaceComposerClient>(conn));
     if (sf != 0) {
         mConnection = conn;
         mControlMemory = sf->getControlBlock();
@@ -574,7 +589,7 @@
     return mControl;
 }
 void SurfaceClient::signalServer() const {
-    mSignalServer->signal();
+    mComposerService->signal();
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index ba1fd9c..35e4af3 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -122,11 +122,20 @@
 status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,
         uint32_t reqUsage)
 {
-    if (format == PIXEL_FORMAT_RGBX_8888)
-        format = PIXEL_FORMAT_RGBA_8888;
-
     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
     status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
+
+    if (err<0 && format == PIXEL_FORMAT_RGBX_8888) {
+        /*
+         * There is currently a bug with some gralloc implementations
+         * not supporting RGBX_8888. In this case, we revert to using RGBA_8888
+         * which is not exactly the same, as GL_REPLACE will yield a different
+         * result.
+         */
+        format = PIXEL_FORMAT_RGBA_8888;
+        err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
+    }
+
     if (err == NO_ERROR) {
         this->width  = w;
         this->height = h;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8f6564a..7672f0f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -344,7 +344,9 @@
  *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
  *          PlaybackCompleted}</p></td>
  *     <td>{Error}</p></td>
- *     <td>Successful invoke of this method does not change the state.</p></td></tr>
+ *     <td>Successful invoke of this method does not change the state. In order for the
+ *         target audio stream type to become effective, this method must be called before
+ *         prepare() or prepareAsync().</p></td></tr>
  * <tr><td>setDataSource </p></td>
  *     <td>{Idle} </p></td>
  *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
@@ -1112,7 +1114,9 @@
 
     /**
      * Sets the audio stream type for this MediaPlayer. See {@link AudioManager}
-     * for a list of stream types.
+     * for a list of stream types. Must call this method before prepare() or
+     * prepareAsync() in order for the target stream type to become effective
+     * thereafter.
      *
      * @param streamtype the audio stream type
      * @see android.media.AudioManager
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index c08f4f5..e39e595 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -114,7 +114,7 @@
 //--- Effect Library Interface Implementation
 //
 
-extern "C" int EffectQueryNumberEffects(int *pNumEffects) {
+extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
     *pNumEffects = 1;
     gEffectIndex = 0;
     return 0;
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index 3181504..202f50b 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -18,7 +18,8 @@
 //
 #define LOG_NDEBUG 0
 #include <cutils/log.h>
-
+#include <stdlib.h>
+#include <string.h>
 #include <stdbool.h>
 #include "EffectReverb.h"
 #include "EffectsMath.h"
@@ -86,7 +87,7 @@
 
 /*--- Effect Library Interface Implementation ---*/
 
-int EffectQueryNumberEffects(int *pNumEffects) {
+int EffectQueryNumberEffects(uint32_t *pNumEffects) {
     *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)
             - 1;
     gEffectIndex = 0;
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index cd14891..578e09e 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -292,7 +292,7 @@
  * Effect API
  *------------------------------------
 */
-int EffectQueryNumberEffects(int *pNumEffects);
+int EffectQueryNumberEffects(uint32_t *pNumEffects);
 int EffectQueryNext(effect_descriptor_t *pDescriptor);
 int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface);
 int EffectRelease(effect_interface_t interface);
diff --git a/media/libeffects/EffectsFactory.c b/media/libeffects/EffectsFactory.c
index 35a10010..6800765 100644
--- a/media/libeffects/EffectsFactory.c
+++ b/media/libeffects/EffectsFactory.c
@@ -39,7 +39,7 @@
 static int init();
 static int loadLibrary(const char *libPath, int *handle);
 static int unloadLibrary(int handle);
-static int numEffectModules();
+static uint32_t numEffectModules();
 static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
 
@@ -96,7 +96,7 @@
 //      Effect Factory Interface functions
 /////////////////////////////////////////////////
 
-int EffectQueryNumberEffects(int *pNumEffects)
+int EffectQueryNumberEffects(uint32_t *pNumEffects)
 {
     int ret = init();
     if (ret < 0) {
@@ -353,8 +353,8 @@
     effect_QueryNextEffect_t queryFx;
     effect_CreateEffect_t createFx;
     effect_ReleaseEffect_t releaseFx;
-    int numFx;
-    int fx;
+    uint32_t numFx;
+    uint32_t fx;
     int ret;
     list_elem_t *e, *descHead = NULL;
     lib_entry_t *l;
@@ -525,9 +525,9 @@
 
 
 
-int numEffectModules() {
+uint32_t numEffectModules() {
     list_elem_t *e = gLibraryList;
-    int cnt = 0;
+    uint32_t cnt = 0;
 
     // Reset pointers for EffectQueryNext()
     gCurLib = e;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index fd2b1ce..a2436ab 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -45,7 +45,7 @@
 // ---------------------------------------------------------------------------
 
 AudioRecord::AudioRecord()
-    : mStatus(NO_INIT)
+    : mStatus(NO_INIT), mSessionId(0)
 {
 }
 
@@ -58,11 +58,12 @@
         uint32_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames)
-    : mStatus(NO_INIT)
+        int notificationFrames,
+        int sessionId)
+    : mStatus(NO_INIT), mSessionId(0)
 {
     mStatus = set(inputSource, sampleRate, format, channels,
-            frameCount, flags, cbf, user, notificationFrames);
+            frameCount, flags, cbf, user, notificationFrames, sessionId);
 }
 
 AudioRecord::~AudioRecord()
@@ -91,7 +92,8 @@
         callback_t cbf,
         void* user,
         int notificationFrames,
-        bool threadCanCallJava)
+        bool threadCanCallJava,
+        int sessionId)
 {
 
     LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
@@ -119,6 +121,7 @@
     if (!AudioSystem::isInputChannel(channels)) {
         return BAD_VALUE;
     }
+
     int channelCount = AudioSystem::popCount(channels);
 
     audio_io_handle_t input = AudioSystem::getInput(inputSource,
@@ -164,6 +167,8 @@
         notificationFrames = frameCount/2;
     }
 
+    mSessionId = sessionId;
+
     // create the IAudioRecord
     status_t status = openRecord(sampleRate, format, channelCount,
                                  frameCount, flags, input);
@@ -414,6 +419,7 @@
                                                        channelCount,
                                                        frameCount,
                                                        ((uint16_t)flags) << 16,
+                                                       &mSessionId,
                                                        &status);
     if (record == 0) {
         LOGE("AudioFlinger could not create record track, status: %d", status);
@@ -532,6 +538,11 @@
     return mInput;
 }
 
+int AudioRecord::getSessionId()
+{
+    return mSessionId;
+}
+
 // -------------------------------------------------------------------------
 
 ssize_t AudioRecord::read(void* buffer, size_t userSize)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 4478abd..372a927 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -364,6 +364,12 @@
     return result;
 }
 
+int AudioSystem::newAudioSessionId() {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return 0;
+    return af->newAudioSessionId();
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c350532..4b61131 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -58,7 +58,8 @@
         uint32_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames)
+        int notificationFrames,
+        int sessionId)
     : mStatus(NO_INIT)
 {
     mStatus = set(streamType, sampleRate, format, channels,
@@ -74,7 +75,8 @@
         uint32_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames)
+        int notificationFrames,
+        int sessionId)
     : mStatus(NO_INIT)
 {
     mStatus = set(streamType, sampleRate, format, channels,
@@ -110,7 +112,8 @@
         void* user,
         int notificationFrames,
         const sp<IMemory>& sharedBuffer,
-        bool threadCanCallJava)
+        bool threadCanCallJava,
+        int sessionId)
 {
 
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
@@ -171,8 +174,11 @@
 
     mVolume[LEFT] = 1.0f;
     mVolume[RIGHT] = 1.0f;
+    mSendLevel = 0;
     mFrameCount = frameCount;
     mNotificationFramesReq = notificationFrames;
+    mSessionId = sessionId;
+
     // create the IAudioTrack
     status_t status = createTrack(streamType, sampleRate, format, channelCount,
                                   frameCount, flags, sharedBuffer, output, true);
@@ -396,19 +402,49 @@
     return mMuted;
 }
 
-void AudioTrack::setVolume(float left, float right)
+status_t AudioTrack::setVolume(float left, float right)
 {
+    if (left > 1.0f || right > 1.0f) {
+        return BAD_VALUE;
+    }
+
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
 
     // write must be atomic
-    mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
+    mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
+
+    return NO_ERROR;
 }
 
 void AudioTrack::getVolume(float* left, float* right)
 {
-    *left  = mVolume[LEFT];
-    *right = mVolume[RIGHT];
+    if (left != NULL) {
+        *left  = mVolume[LEFT];
+    }
+    if (right != NULL) {
+        *right = mVolume[RIGHT];
+    }
+}
+
+status_t AudioTrack::setSendLevel(float level)
+{
+    if (level > 1.0f) {
+        return BAD_VALUE;
+    }
+
+    mSendLevel = level;
+
+    mCblk->sendLevel = uint16_t(level * 0x1000);
+
+    return NO_ERROR;
+}
+
+void AudioTrack::getSendLevel(float* level)
+{
+    if (level != NULL) {
+        *level  = mSendLevel;
+    }
 }
 
 status_t AudioTrack::setSampleRate(int rate)
@@ -563,6 +599,16 @@
             mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
 }
 
+int AudioTrack::getSessionId()
+{
+    return mSessionId;
+}
+
+status_t AudioTrack::attachAuxEffect(int effectId)
+{
+    return mAudioTrack->attachAuxEffect(effectId);
+}
+
 // -------------------------------------------------------------------------
 
 status_t AudioTrack::createTrack(
@@ -647,6 +693,7 @@
                                                       ((uint16_t)flags) << 16,
                                                       sharedBuffer,
                                                       output,
+                                                      &mSessionId,
                                                       &status);
 
     if (track == 0) {
@@ -672,7 +719,8 @@
         mCblk->stepUser(mCblk->frameCount);
     }
 
-    mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000);
+    mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
+    mCblk->sendLevel = uint16_t(mSendLevel * 0x1000);
     mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
     mCblk->waitTimeMs = 0;
     mRemainingFrames = mNotificationFramesAct;
@@ -1016,7 +1064,7 @@
     : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
     userBase(0), serverBase(0), buffers(0), frameCount(0),
     loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
-    flags(0)
+    flags(0), sendLevel(0)
 {
 }
 
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 47bcc12..f2a8db3 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -62,7 +62,14 @@
     SET_STREAM_OUTPUT,
     SET_VOICE_VOLUME,
     GET_RENDER_POSITION,
-    GET_INPUT_FRAMES_LOST
+    GET_INPUT_FRAMES_LOST,
+    NEW_AUDIO_SESSION_ID,
+    LOAD_EFFECT_LIBRARY,
+    UNLOAD_EFFECT_LIBRARY,
+    QUERY_NUM_EFFECTS,
+    QUERY_NEXT_EFFECT,
+    GET_EFFECT_DESCRIPTOR,
+    CREATE_EFFECT
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -83,6 +90,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 int output,
+                                int *sessionId,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -97,10 +105,19 @@
         data.writeInt32(flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
         data.writeInt32(output);
+        int lSessionId = 0;
+        if (sessionId != NULL) {
+            lSessionId = *sessionId;
+        }
+        data.writeInt32(lSessionId);
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("createTrack error: %s", strerror(-lStatus));
         } else {
+            lSessionId = reply.readInt32();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
             lStatus = reply.readInt32();
             track = interface_cast<IAudioTrack>(reply.readStrongBinder());
         }
@@ -118,6 +135,7 @@
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
+                                int *sessionId,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -130,10 +148,19 @@
         data.writeInt32(channelCount);
         data.writeInt32(frameCount);
         data.writeInt32(flags);
+        int lSessionId = 0;
+        if (sessionId != NULL) {
+            lSessionId = *sessionId;
+        }
+        data.writeInt32(lSessionId);
         status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("openRecord error: %s", strerror(-lStatus));
         } else {
+            lSessionId = reply.readInt32();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
             lStatus = reply.readInt32();
             record = interface_cast<IAudioRecord>(reply.readStrongBinder());
         }
@@ -497,6 +524,157 @@
         remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
         return reply.readInt32();
     }
+
+    virtual int newAudioSessionId()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply);
+        int id = 0;
+        if (status == NO_ERROR) {
+            id = reply.readInt32();
+        }
+        return id;
+    }
+
+    virtual status_t loadEffectLibrary(const char *libPath, int *handle)
+    {
+        if (libPath == NULL || handle == NULL) {
+            return BAD_VALUE;
+        }
+        *handle = 0;
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeCString(libPath);
+        status_t status = remote()->transact(LOAD_EFFECT_LIBRARY, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+            if (status == NO_ERROR) {
+                *handle = reply.readInt32();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t unloadEffectLibrary(int handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(handle);
+        status_t status = remote()->transact(UNLOAD_EFFECT_LIBRARY, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(QUERY_NUM_EFFECTS, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        if (numEffects) {
+            *numEffects = (uint32_t)reply.readInt32();
+        }
+        return NO_ERROR;
+    }
+
+    virtual status_t queryNextEffect(effect_descriptor_t *pDescriptor)
+    {
+        if (pDescriptor == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(QUERY_NEXT_EFFECT, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        reply.read(pDescriptor, sizeof(effect_descriptor_t));
+        return NO_ERROR;
+    }
+
+    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *pDescriptor)
+    {
+        if (pUuid == NULL || pDescriptor == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(pUuid, sizeof(effect_uuid_t));
+        status_t status = remote()->transact(GET_EFFECT_DESCRIPTOR, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        reply.read(pDescriptor, sizeof(effect_descriptor_t));
+        return NO_ERROR;
+    }
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                                    effect_descriptor_t *pDesc,
+                                    const sp<IEffectClient>& client,
+                                    int32_t priority,
+                                    int output,
+                                    int sessionId,
+                                    status_t *status,
+                                    int *id,
+                                    int *enabled)
+    {
+        Parcel data, reply;
+        sp<IEffect> effect;
+
+        if (pDesc == NULL) {
+             return effect;
+             if (status) {
+                 *status = BAD_VALUE;
+             }
+         }
+
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.write(pDesc, sizeof(effect_descriptor_t));
+        data.writeStrongBinder(client->asBinder());
+        data.writeInt32(priority);
+        data.writeInt32(output);
+        data.writeInt32(sessionId);
+
+        status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
+        if (lStatus != NO_ERROR) {
+            LOGE("createEffect error: %s", strerror(-lStatus));
+        } else {
+            lStatus = reply.readInt32();
+            int tmp = reply.readInt32();
+            if (id) {
+                *id = tmp;
+            }
+            tmp = reply.readInt32();
+            if (enabled) {
+                *enabled = tmp;
+            }
+            effect = interface_cast<IEffect>(reply.readStrongBinder());
+            reply.read(pDesc, sizeof(effect_descriptor_t));
+        }
+        if (status) {
+            *status = lStatus;
+        }
+
+        return effect;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -518,10 +696,12 @@
             uint32_t flags = data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
             int output = data.readInt32();
+            int sessionId = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, output, &status);
+                    channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
+            reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
@@ -535,9 +715,11 @@
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
+            int sessionId = data.readInt32();
             status_t status;
             sp<IAudioRecord> record = openRecord(pid, input,
-                    sampleRate, format, channelCount, bufferCount, flags, &status);
+                    sampleRate, format, channelCount, bufferCount, flags, &sessionId, &status);
+            reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(record->asBinder());
             return NO_ERROR;
@@ -768,7 +950,79 @@
             reply->writeInt32(getInputFramesLost(ioHandle));
             return NO_ERROR;
         } break;
+        case NEW_AUDIO_SESSION_ID: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32(newAudioSessionId());
+            return NO_ERROR;
+        } break;
+        case LOAD_EFFECT_LIBRARY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int handle;
+            status_t status = loadEffectLibrary(data.readCString(), &handle);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(handle);
+            }
+            return NO_ERROR;
+        }
+        case UNLOAD_EFFECT_LIBRARY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32(unloadEffectLibrary(data.readInt32()));
+            return NO_ERROR;
+        }
+        case QUERY_NUM_EFFECTS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            uint32_t numEffects;
+            status_t status = queryNumberEffects(&numEffects);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32((int32_t)numEffects);
+            }
+            return NO_ERROR;
+        }
+        case QUERY_NEXT_EFFECT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            effect_descriptor_t desc;
+            status_t status = queryNextEffect(&desc);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&desc, sizeof(effect_descriptor_t));
+            }
+            return NO_ERROR;
+        }
+        case GET_EFFECT_DESCRIPTOR: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            effect_uuid_t uuid;
+            data.read(&uuid, sizeof(effect_uuid_t));
+            effect_descriptor_t desc;
+            status_t status = getEffectDescriptor(&uuid, &desc);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&desc, sizeof(effect_descriptor_t));
+            }
+            return NO_ERROR;
+        }
+        case CREATE_EFFECT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            pid_t pid = data.readInt32();
+            effect_descriptor_t desc;
+            data.read(&desc, sizeof(effect_descriptor_t));
+            sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
+            int32_t priority = data.readInt32();
+            int output = data.readInt32();
+            int sessionId = data.readInt32();
+            status_t status;
+            int id;
+            int enabled;
 
+            sp<IEffect> effect = createEffect(pid, &desc, client, priority, output, sessionId, &status, &id, &enabled);
+            reply->writeInt32(status);
+            reply->writeInt32(id);
+            reply->writeInt32(enabled);
+            reply->writeStrongBinder(effect->asBinder());
+            reply->write(&desc, sizeof(effect_descriptor_t));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 01ffd75..bc8ff34 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -34,7 +34,8 @@
     STOP,
     FLUSH,
     MUTE,
-    PAUSE
+    PAUSE,
+    ATTACH_AUX_EFFECT
 };
 
 class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -97,7 +98,21 @@
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
         }
         return cblk;
-    }    
+    }
+
+    virtual status_t attachAuxEffect(int effectId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt32(effectId);
+        status_t status = remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        } else {
+            LOGW("attachAuxEffect() error: %s", strerror(-status));
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -138,6 +153,11 @@
             pause();
             return NO_ERROR;
         }
+        case ATTACH_AUX_EFFECT: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            reply->writeInt32(attachAuxEffect(data.readInt32()));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 8d15013..f00fad8 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -40,6 +40,7 @@
         ShoutcastSource.cpp       \
         StagefrightMediaScanner.cpp \
         StagefrightMetadataRetriever.cpp \
+        ThrottledSource.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
         WAVExtractor.cpp          \
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 944a0c1..b6ed56b 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -58,13 +58,14 @@
     status_t mFinalStatus;
     int64_t mSeekTimeUs;
     int64_t mCacheDurationUs;
+    size_t mCacheSizeBytes;
     bool mPrefetcherStopped;
     bool mCurrentlyPrefetching;
 
     List<MediaBuffer *> mCachedBuffers;
 
     // Returns true iff source is currently caching.
-    bool getCacheDurationUs(int64_t *durationUs);
+    bool getCacheDurationUs(int64_t *durationUs, size_t *totalSize = NULL);
 
     void updateCacheDuration_l();
     void clearCache_l();
@@ -125,21 +126,31 @@
     return 0;
 }
 
-// Cache about 10secs for each source.
-static int64_t kMaxCacheDurationUs = 10000000ll;
+// Cache at most 1 min for each source.
+static int64_t kMaxCacheDurationUs = 60 * 1000000ll;
+
+// At the same time cache at most 5MB per source.
+static size_t kMaxCacheSizeBytes = 5 * 1024 * 1024;
+
+// If the amount of cached data drops below this,
+// fill the cache up to the max duration again.
+static int64_t kLowWaterDurationUs = 5000000ll;
 
 void Prefetcher::threadFunc() {
+    bool fillingCache = false;
+
     for (;;) {
         sp<PrefetchedSource> minSource;
+        int64_t minCacheDurationUs = -1;
 
         {
             Mutex::Autolock autoLock(mLock);
             if (mDone) {
                 break;
             }
-            mCondition.waitRelative(mLock, 10000000ll);
+            mCondition.waitRelative(
+                    mLock, fillingCache ? 10000000ll : 1000000000ll);
 
-            int64_t minCacheDurationUs = -1;
             ssize_t minIndex = -1;
             for (size_t i = 0; i < mSources.size(); ++i) {
                 sp<PrefetchedSource> source = mSources[i].promote();
@@ -149,11 +160,18 @@
                 }
 
                 int64_t cacheDurationUs;
-                if (!source->getCacheDurationUs(&cacheDurationUs)) {
+                size_t cacheSizeBytes;
+                if (!source->getCacheDurationUs(&cacheDurationUs, &cacheSizeBytes)) {
                     continue;
                 }
 
-                if (cacheDurationUs >= kMaxCacheDurationUs) {
+                if (cacheSizeBytes > kMaxCacheSizeBytes) {
+                    LOGI("max cache size reached");
+                    continue;
+                }
+
+                if (mSources.size() > 1 && cacheDurationUs >= kMaxCacheDurationUs) {
+                    LOGI("max duration reached, size = %d bytes", cacheSizeBytes);
                     continue;
                 }
 
@@ -165,14 +183,26 @@
             }
 
             if (minIndex < 0) {
+                if (fillingCache) {
+                    LOGV("[%p] done filling the cache, above high water mark.",
+                         this);
+                    fillingCache = false;
+                }
                 continue;
             }
         }
 
-        // Make sure not to hold the lock while calling into the source.
-        // The lock guards the list of sources, not the individual sources
-        // themselves.
-        minSource->cacheMore();
+        if (!fillingCache && minCacheDurationUs < kLowWaterDurationUs) {
+            LOGI("[%p] cache below low water mark, filling cache.", this);
+            fillingCache = true;
+        }
+
+        if (fillingCache) {
+            // Make sure not to hold the lock while calling into the source.
+            // The lock guards the list of sources, not the individual sources
+            // themselves.
+            minSource->cacheMore();
+        }
     }
 
     Mutex::Autolock autoLock(mLock);
@@ -250,6 +280,7 @@
       mReachedEOS(false),
       mSeekTimeUs(0),
       mCacheDurationUs(0),
+      mCacheSizeBytes(0),
       mPrefetcherStopped(false),
       mCurrentlyPrefetching(false) {
 }
@@ -323,6 +354,7 @@
     *out = *mCachedBuffers.begin();
     mCachedBuffers.erase(mCachedBuffers.begin());
     updateCacheDuration_l();
+    mCacheSizeBytes -= (*out)->size();
 
     return OK;
 }
@@ -331,10 +363,14 @@
     return mSource->getFormat();
 }
 
-bool PrefetchedSource::getCacheDurationUs(int64_t *durationUs) {
+bool PrefetchedSource::getCacheDurationUs(
+        int64_t *durationUs, size_t *totalSize) {
     Mutex::Autolock autoLock(mLock);
 
     *durationUs = mCacheDurationUs;
+    if (totalSize != NULL) {
+        *totalSize = mCacheSizeBytes;
+    }
 
     if (!mStarted || mReachedEOS) {
         return false;
@@ -397,6 +433,7 @@
 
     mCachedBuffers.push_back(copy);
     updateCacheDuration_l();
+    mCacheSizeBytes += copy->size();
 
     mCurrentlyPrefetching = false;
     mCondition.signal();
@@ -425,6 +462,7 @@
     }
 
     updateCacheDuration_l();
+    mCacheSizeBytes = 0;
 }
 
 void PrefetchedSource::onPrefetcherStopped() {
diff --git a/media/libstagefright/ThrottledSource.cpp b/media/libstagefright/ThrottledSource.cpp
new file mode 100644
index 0000000..4711f7c6
--- /dev/null
+++ b/media/libstagefright/ThrottledSource.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "include/ThrottledSource.h"
+
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+static int64_t getNowUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
+}
+
+ThrottledSource::ThrottledSource(
+        const sp<DataSource> &source,
+        int32_t bandwidthLimitBytesPerSecond)
+    : mSource(source),
+      mBandwidthLimitBytesPerSecond(bandwidthLimitBytesPerSecond),
+      mStartTimeUs(-1),
+      mTotalTransferred(0) {
+    CHECK(mBandwidthLimitBytesPerSecond > 0);
+}
+
+status_t ThrottledSource::initCheck() const {
+    return mSource->initCheck();
+}
+
+ssize_t ThrottledSource::readAt(off_t offset, void *data, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    ssize_t n = mSource->readAt(offset, data, size);
+
+    if (n <= 0) {
+        return n;
+    }
+
+    mTotalTransferred += n;
+
+    int64_t nowUs = getNowUs();
+
+    if (mStartTimeUs < 0) {
+        mStartTimeUs = nowUs;
+    }
+
+    // How long would it have taken to transfer everything we ever
+    // transferred given the limited bandwidth.
+    int64_t durationUs =
+        mTotalTransferred * 1000000ll / mBandwidthLimitBytesPerSecond;
+
+    int64_t whenUs = mStartTimeUs + durationUs;
+
+    if (whenUs > nowUs) {
+        usleep(whenUs - nowUs);
+    }
+
+    return n;
+}
+
+status_t ThrottledSource::getSize(off_t *size) {
+    return mSource->getSize(size);
+}
+
+uint32_t ThrottledSource::flags() {
+    return mSource->flags();
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
new file mode 100644
index 0000000..88164b3
--- /dev/null
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -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.
+ */
+
+#ifndef THROTTLED_SOURCE_H_
+
+#define THROTTLED_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct ThrottledSource : public DataSource {
+    ThrottledSource(
+            const sp<DataSource> &source,
+            int32_t bandwidthLimitBytesPerSecond);
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off_t *size);
+    virtual uint32_t flags();
+
+private:
+    Mutex mLock;
+
+    sp<DataSource> mSource;
+    int32_t mBandwidthLimitBytesPerSecond;
+    int64_t mStartTimeUs;
+    size_t mTotalTransferred;
+
+    ThrottledSource(const ThrottledSource &);
+    ThrottledSource &operator=(const ThrottledSource &);
+};
+
+}  // namespace android
+
+#endif  // THROTTLED_SOURCE_H_
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 9e9ae2f..ec9f17b 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -41,7 +41,8 @@
 
 LOCAL_CFLAGS := -DMTP_DEVICE
 
-LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright
+LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libcutils \
+	libmedia
 
 include $(BUILD_EXECUTABLE)
 
@@ -91,7 +92,7 @@
 #LOCAL_LDLIBS := -lpthread
 
 LOCAL_C_INCLUDES := external/sqlite/dist
-LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright
+LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libmedia
 
 
 LOCAL_CFLAGS := -g
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
new file mode 100644
index 0000000..4c83768
--- /dev/null
+++ b/packages/SystemUI/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := services
+
+LOCAL_PACKAGE_NAME := SystemUI
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
new file mode 100644
index 0000000..3f5b69d
--- /dev/null
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.systemui"
+        android:sharedUserId="android.uid.system">
+
+    <application
+        android:allowClearUserData="false"
+        android:label="@string/app_label"
+        android:icon="@drawable/ic_launcher_settings">
+                 
+        <receiver
+            android:name=".statusbar.StatusBarStarter"
+            >
+            <intent-filter>
+                <action android:name="com.android.internal.policy.statusbar.START" />
+            </intent-filter>
+        </receiver>
+        <service
+            android:name=".statusbar.PhoneStatusBarService"
+            android:exported="false"
+            />
+    </application>
+</manifest>
diff --git a/packages/SystemUI/MODULE_LICENSE_APACHE2 b/packages/SystemUI/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/SystemUI/MODULE_LICENSE_APACHE2
diff --git a/packages/SystemUI/NOTICE b/packages/SystemUI/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/SystemUI/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/core/res/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
similarity index 100%
rename from core/res/res/drawable-hdpi/battery_low_battery.png
rename to packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png
new file mode 100644
index 0000000..baafed6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png
new file mode 100644
index 0000000..175197b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
new file mode 100644
index 0000000..ec1feff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png
new file mode 100644
index 0000000..c1f9a0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png
new file mode 100644
index 0000000..0ea3f40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..ff34a7f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
new file mode 100644
index 0000000..744178f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/shade_bg.png b/packages/SystemUI/res/drawable-hdpi/shade_bg.png
new file mode 100644
index 0000000..3d00cd0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/shade_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/shade_handlebar.9.png b/packages/SystemUI/res/drawable-hdpi/shade_handlebar.9.png
new file mode 100644
index 0000000..f313ffb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/shade_handlebar.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/shade_header_background.9.png b/packages/SystemUI/res/drawable-hdpi/shade_header_background.9.png
new file mode 100644
index 0000000..37b5fef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/shade_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_notify_alarm.png
rename to packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
new file mode 100755
index 0000000..1c7f9db
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
new file mode 100644
index 0000000..96dc085
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_no_sim.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_2.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_3.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_4.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_ringer_silent.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_2.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_3.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_4.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_null.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tty_mode.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
new file mode 100644
index 0000000..a4be298
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_app_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_app_background_normal.9.png
new file mode 100644
index 0000000..4fbfa4f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_app_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_focus.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_focus.9.png
new file mode 100644
index 0000000..0876bc6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_focus.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_normal.9.png
new file mode 100644
index 0000000..c01c018
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_pressed.9.png
new file mode 100644
index 0000000..343e4ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/title_bar_portrait.9.png b/packages/SystemUI/res/drawable-hdpi/title_bar_portrait.9.png
new file mode 100644
index 0000000..70f7cc2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png
new file mode 100644
index 0000000..e6dab63
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
similarity index 100%
rename from core/res/res/drawable-mdpi/battery_low_battery.png
rename to packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png
new file mode 100644
index 0000000..bcedd5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png
new file mode 100644
index 0000000..ac6260f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
new file mode 100644
index 0000000..4ee1b3f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png
new file mode 100644
index 0000000..25e38f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png
new file mode 100644
index 0000000..cc209c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..b08ad3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
similarity index 76%
copy from core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
copy to packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
index 8e6aaca..1a3063c4 100644
--- a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/shade_bg.png b/packages/SystemUI/res/drawable-mdpi/shade_bg.png
new file mode 100644
index 0000000..941d3b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/shade_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/shade_handlebar.9.png b/packages/SystemUI/res/drawable-mdpi/shade_handlebar.9.png
new file mode 100644
index 0000000..9cbd9fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/shade_handlebar.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png b/packages/SystemUI/res/drawable-mdpi/shade_header_background.9.png
similarity index 76%
copy from core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
copy to packages/SystemUI/res/drawable-mdpi/shade_header_background.9.png
index 8e6aaca..fa9a90c 100644
--- a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/shade_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_notify_alarm.png
rename to packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
new file mode 100644
index 0000000..e129ba9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_no_sim.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_2.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_3.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_4.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_ringer_silent.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_2.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_3.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_4.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_null.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tty_mode.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
new file mode 100644
index 0000000..eb7c1a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
similarity index 78%
rename from core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
rename to packages/SystemUI/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
index 8e6aaca..c079615 100644
--- a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_focus.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_focus.9.png
new file mode 100644
index 0000000..c3e24158
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_focus.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_normal.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_normal.9.png
new file mode 100644
index 0000000..b8e399d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_pressed.9.png
new file mode 100644
index 0000000..02b4e9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/title_bar_portrait.9.png b/packages/SystemUI/res/drawable-mdpi/title_bar_portrait.9.png
new file mode 100644
index 0000000..13b18d8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png
new file mode 100644
index 0000000..dbcefee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/btn_default_small.xml b/packages/SystemUI/res/drawable/btn_default_small.xml
new file mode 100644
index 0000000..5485ea0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/btn_default_small.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/btn_default_small_normal" />
+    <item android:state_window_focused="false" android:state_enabled="false"
+        android:drawable="@drawable/btn_default_small_normal_disable" />
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/btn_default_small_pressed" />
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/btn_default_small_selected" />
+    <item android:state_enabled="true"
+        android:drawable="@drawable/btn_default_small_normal" />
+    <item android:state_focused="true"
+        android:drawable="@drawable/btn_default_small_normal_disable_focused" />
+    <item
+         android:drawable="@drawable/btn_default_small_normal_disable" />
+</selector>
+
diff --git a/core/res/res/drawable/stat_sys_gps_acquiring_anim.xml b/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
similarity index 90%
rename from core/res/res/drawable/stat_sys_gps_acquiring_anim.xml
rename to packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
index 954c19c..393697c 100644
--- a/core/res/res/drawable/stat_sys_gps_acquiring_anim.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
@@ -21,5 +21,5 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:oneshot="false">
     <item android:drawable="@drawable/stat_sys_gps_acquiring" android:duration="500" />
-    <item android:drawable="@drawable/stat_sys_gps_on" android:duration="500" />
+    <item android:drawable="@*android:drawable/stat_sys_gps_on" android:duration="500" />
 </animation-list>
diff --git a/core/res/res/drawable/stat_sys_roaming_cdma_flash.xml b/packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml
similarity index 100%
rename from core/res/res/drawable/stat_sys_roaming_cdma_flash.xml
rename to packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml
diff --git a/core/res/res/layout/battery_low.xml b/packages/SystemUI/res/layout/battery_low.xml
similarity index 100%
rename from core/res/res/layout/battery_low.xml
rename to packages/SystemUI/res/layout/battery_low.xml
diff --git a/core/res/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
similarity index 70%
rename from core/res/res/layout/status_bar.xml
rename to packages/SystemUI/res/layout/status_bar.xml
index 2237ee4..5fe8e79 100644
--- a/core/res/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -19,8 +19,9 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<com.android.server.status.StatusBarView xmlns:android="http://schemas.android.com/apk/res/android" 
-    android:background="@drawable/statusbar_background"
+<com.android.systemui.statusbar.StatusBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@drawable/status_bar_background"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -31,7 +32,7 @@
         android:layout_height="match_parent"
         android:orientation="horizontal">
             
-        <com.android.server.status.IconMerger android:id="@+id/notificationIcons"
+        <com.android.systemui.statusbar.IconMerger android:id="@+id/notificationIcons"
             android:layout_width="0dip"
             android:layout_weight="1"
             android:layout_height="match_parent"
@@ -47,6 +48,17 @@
             android:paddingRight="6dip"
             android:gravity="center_vertical"
             android:orientation="horizontal"/>    
+
+        <com.android.systemui.statusbar.Clock
+            android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:singleLine="true"
+            android:paddingRight="6dip"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            android:gravity="center_vertical|left"
+            />
     </LinearLayout>
         
     <LinearLayout android:id="@+id/ticker"
@@ -60,44 +72,44 @@
             android:layout_height="match_parent"
             android:layout_marginRight="8dip"
             >
-            <com.android.server.status.AnimatedImageView
+            <com.android.systemui.statusbar.AnimatedImageView
                 android:layout_width="25dip"
                 android:layout_height="25dip"
                 />
-            <com.android.server.status.AnimatedImageView
+            <com.android.systemui.statusbar.AnimatedImageView
                 android:layout_width="25dip"
                 android:layout_height="25dip"
                 />
         </ImageSwitcher>
-        <com.android.server.status.TickerView android:id="@+id/tickerText"
+        <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText"
             android:layout_width="0dip"
             android:layout_weight="1"
             android:layout_height="wrap_content"
             android:paddingTop="2dip"
             android:paddingRight="10dip">
             <TextView
-                android:textAppearance="@style/TextAppearance.StatusBar.Ticker"
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
                 />
             <TextView
-                android:textAppearance="@style/TextAppearance.StatusBar.Ticker"
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
                 />
-        </com.android.server.status.TickerView>
+        </com.android.systemui.statusbar.TickerView>
     </LinearLayout>
 
-    <com.android.server.status.DateView android:id="@+id/date"
-        android:textAppearance="@style/TextAppearance.StatusBar.Icon"
+    <com.android.systemui.statusbar.DateView android:id="@+id/date"
+        android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:singleLine="true"
         android:gravity="center_vertical|left"
         android:paddingLeft="6px"
         android:paddingRight="6px"
-        android:background="@drawable/statusbar_background"
+        android:background="@drawable/status_bar_background"
         />
-</com.android.server.status.StatusBarView>
+</com.android.systemui.statusbar.StatusBarView>
diff --git a/core/res/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
similarity index 77%
rename from core/res/res/layout/status_bar_expanded.xml
rename to packages/SystemUI/res/layout/status_bar_expanded.xml
index 68eb922..b5b1b50 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.server.status.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -31,9 +31,9 @@
         android:paddingTop="3dp"
         android:paddingBottom="5dp"
         android:paddingRight="3dp"
-        android:background="@drawable/status_bar_header_background"
+        android:background="@drawable/shade_header_background"
         >
-        <LinearLayout
+        <com.android.systemui.statusbar.CarrierLabel
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
@@ -41,25 +41,10 @@
             android:layout_marginLeft="5dp"
             android:layout_gravity="center_vertical"
             android:paddingBottom="1dp"
-            android:orientation="vertical"
-            >
-                <TextView android:id="@+id/plmnLabel"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical"
-                    android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:paddingLeft="4dp"
-                    />
-                <TextView android:id="@+id/spnLabel"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical"
-                    android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:paddingLeft="4dp"
-                    />
-        </LinearLayout>
+            android:paddingLeft="4dp"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textColor="?android:attr/textColorSecondary"
+            />
         <TextView android:id="@+id/clear_all_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -67,7 +52,7 @@
             android:layout_marginTop="4dp"
             android:layout_marginBottom="1dp"
             android:textSize="14sp"
-            android:textColor="?android:attr/textColorPrimaryInverse"
+            android:textColor="#ff000000"
             android:text="@string/status_bar_clear_all_button"
             style="?android:attr/buttonStyle"
             android:paddingLeft="15dp"
@@ -87,7 +72,7 @@
             android:layout_height="match_parent"
             android:fadingEdge="none"
             >
-            <com.android.server.status.NotificationLinearLayout
+            <com.android.systemui.statusbar.NotificationLinearLayout
                 android:id="@+id/notificationLinearLayout"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -130,7 +115,7 @@
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
                     />
-            </com.android.server.status.NotificationLinearLayout>
+            </com.android.systemui.statusbar.NotificationLinearLayout>
         </ScrollView>
 
         <ImageView
@@ -141,4 +126,4 @@
         />
 
     </FrameLayout>
-</com.android.server.status.ExpandedView>
+</com.android.systemui.statusbar.ExpandedView>
diff --git a/core/res/res/layout/status_bar_icon.xml b/packages/SystemUI/res/layout/status_bar_icon.xml
similarity index 95%
rename from core/res/res/layout/status_bar_icon.xml
rename to packages/SystemUI/res/layout/status_bar_icon.xml
index 0536792..21d606f 100644
--- a/core/res/res/layout/status_bar_icon.xml
+++ b/packages/SystemUI/res/layout/status_bar_icon.xml
@@ -25,7 +25,7 @@
     android:layout_height="25dp"
     >
 
-    <com.android.server.status.AnimatedImageView android:id="@+id/image"
+    <com.android.systemui.statusbar.AnimatedImageView android:id="@+id/image"
         android:layout_width="match_parent" 
         android:layout_height="match_parent"
         />
diff --git a/core/res/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
similarity index 77%
rename from core/res/res/layout/status_bar_tracking.xml
rename to packages/SystemUI/res/layout/status_bar_tracking.xml
index c0a7a97..a2b40e6 100644
--- a/core/res/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -15,7 +15,8 @@
     limitations under the License.
 -->
 
-<com.android.server.status.TrackingView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.TrackingView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:visibility="gone"
     android:focusable="true"
@@ -25,13 +26,13 @@
     android:paddingRight="0px"
     >
 
-    <com.android.server.status.TrackingPatternView
+    <com.android.systemui.statusbar.TrackingPatternView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         />
 
-    <com.android.server.status.CloseDragHandle android:id="@+id/close"
+    <com.android.systemui.statusbar.CloseDragHandle android:id="@+id/close"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
@@ -41,8 +42,9 @@
             android:layout_height="wrap_content"
             android:layout_gravity="bottom"
             android:scaleType="fitXY"
-            android:src="@drawable/status_bar_close_on"/>
+            android:src="@drawable/shade_handlebar"
+            />
 
-    </com.android.server.status.CloseDragHandle>
+    </com.android.systemui.statusbar.CloseDragHandle>
 
-</com.android.server.status.TrackingView>
+</com.android.systemui.statusbar.TrackingView>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
new file mode 100644
index 0000000..dbb0e0f
--- /dev/null
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
+         icons in the status bar that are not notifications. -->
+    <string-array name="status_bar_icon_order">
+        <item><xliff:g id="id">TODO: Remove; not used.</xliff:g></item>
+    </string-array>
+
+</resources>
diff --git a/core/res/res/drawable/status_icon_background.xml b/packages/SystemUI/res/values/config.xml
similarity index 61%
rename from core/res/res/drawable/status_icon_background.xml
rename to packages/SystemUI/res/values/config.xml
index 9846165..8ea46e5 100644
--- a/core/res/res/drawable/status_icon_background.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/drawable/status_icon_background.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** Copyright 2009, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
 ** you may not use this file except in compliance with the License. 
@@ -18,7 +17,10 @@
 */
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="true" android:drawable="@drawable/icon_highlight_rectangle" />
-    <item android:drawable="@color/transparent" />
-</selector>
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices -->
+    <bool name="config_hspa_data_distinguishable">false</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values/defaults.xml b/packages/SystemUI/res/values/defaults.xml
new file mode 100644
index 0000000..34302c4
--- /dev/null
+++ b/packages/SystemUI/res/values/defaults.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+-->
+<resources>
+    <bool name="def_dim_screen">true</bool>
+    <integer name="def_screen_off_timeout">60000</integer>
+    <bool name="def_airplane_mode_on">false</bool>
+    <!-- Comma-separated list of bluetooth, wifi, and cell. -->
+    <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string>
+    <string name="airplane_mode_toggleable_radios" translatable="false">wifi</string>
+    <bool name="def_auto_time">true</bool>
+    <bool name="def_accelerometer_rotation">true</bool>
+    <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
+    <integer name="def_screen_brightness">102</integer>
+    <bool name="def_screen_brightness_automatic_mode">false</bool>
+    <fraction name="def_window_animation_scale">100%</fraction>
+    <fraction name="def_window_transition_scale">100%</fraction>
+    <bool name="def_haptic_feedback">true</bool>
+    
+    <bool name="def_bluetooth_on">false</bool>
+    <bool name="def_install_non_market_apps">false</bool>
+    <!-- Comma-separated list of location providers. 
+         Network location is off by default because it requires
+         user opt-in via Setup Wizard or Settings.  
+    -->
+    <string name="def_location_providers_allowed" translatable="false">gps</string>
+    <bool name="assisted_gps_enabled">true</bool>
+    <!--  0 == mobile, 1 == wifi. -->
+    <integer name="def_network_preference">1</integer>
+    <bool name="def_usb_mass_storage_enabled">true</bool>
+    <bool name="def_wifi_on">false</bool>
+    <bool name="def_networks_available_notification_on">true</bool>
+    
+    <bool name="def_backup_enabled">false</bool>
+    <string name="def_backup_transport" translatable="false"></string>
+    <!-- Default value for whether or not to pulse the notification LED when there is a 
+         pending notification -->
+    <bool name="def_notification_pulse">true</bool>
+
+    <bool name="def_mount_play_notification_snd">true</bool>
+    <bool name="def_mount_ums_autostart">false</bool>
+    <bool name="def_mount_ums_prompt">true</bool>
+    <bool name="def_mount_ums_notify_enabled">true</bool>
+    <!-- Enable User preference for setting install location -->
+    <bool name="set_install_location">true</bool>
+    <!-- Default install location if user preference for setting install location is turned on. -->
+    <integer name="def_install_location">2</integer>
+
+    <!-- user interface sound effects -->
+    <integer name="def_power_sounds_enabled">1</integer>
+    <string name="def_low_battery_sound" translatable="false">/system/media/audio/ui/LowBattery.ogg</string>
+    <integer name="def_dock_sounds_enabled">0</integer>
+    <string name="def_desk_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
+    <string name="def_desk_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+    <string name="def_car_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
+    <string name="def_car_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+    <integer name="def_lockscreen_sounds_enabled">0</integer>
+    <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
+    <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+
+    <!-- Default for Settings.System.VIBRATE_IN_SILENT -->
+    <bool name="def_vibrate_in_silent">true</bool>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
new file mode 100644
index 0000000..93cf377
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2006, 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>
+    <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
+    <dimen name="status_bar_edge_ignore">5dp</dimen>
+</resources>
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
new file mode 100644
index 0000000..ba3a3d1
--- /dev/null
+++ b/packages/SystemUI/res/values/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of the status bar as seen in the applications info settings page. -->
+    <string name="app_label">Status Bar</string>
+
+    <!-- The text for the button in the notification window-shade that clears
+         all of the currently visible notifications. -->
+    <string name="status_bar_clear_all_button">Clear</string>
+
+    <!-- The label in the bar at the top of the status bar when there are no notifications
+         showing. -->
+    <string name="status_bar_no_notifications_title">No notifications</string>
+
+    <!-- The label for the group of notifications for ongoing events in the opened version of
+         the status bar.  An ongoing call is the prime example of this.  The MP3 music player
+         might be another example.  -->
+    <string name="status_bar_ongoing_events_title">Ongoing</string>
+
+    <!-- The label for the group of notifications for recent events in the opened version of
+         the status bar.  Recently received text messsages (SMS), emails, calendar alerts, etc. -->
+    <string name="status_bar_latest_events_title">Notifications</string>
+
+    <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert. -->
+    <string name="battery_low_title">Please connect charger</string>
+
+    <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. -->
+    <string name="battery_low_subtitle">The battery is getting low:</string>
+
+    <!-- A message that appears when the battery level is getting low in a dialog.  This is appened to the subtitle of the low battery alert. -->
+    <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g>
+    or less remaining.</string>
+
+    <!-- When the battery is low, this is the label of the button to go to the
+         power usage activity to find out what drained the battery. -->
+    <string name="battery_low_why">Battery use</string>
+
+</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
new file mode 100644
index 0000000..10fa930
--- /dev/null
+++ b/packages/SystemUI/res/values/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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 xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="TextAppearance.StatusBar.Title" parent="@android:style/TextAppearance.StatusBar">
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+
+
+</resources>
diff --git a/packages/SystemUI/res/xml/bookmarks.xml b/packages/SystemUI/res/xml/bookmarks.xml
new file mode 100644
index 0000000..dfaeeaf
--- /dev/null
+++ b/packages/SystemUI/res/xml/bookmarks.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bookmarks>
+    <bookmark
+        package="com.android.browser"
+        class="com.android.browser.BrowserActivity"
+        shortcut="b" />
+    <bookmark
+        package="com.android.contacts"
+        class="com.android.contacts.DialtactsContactsEntryActivity"
+        shortcut="c" />
+    <bookmark
+        package="com.android.email"
+        class="com.android.email.activity.Welcome"
+        shortcut="e" />
+    <bookmark
+        package="com.google.android.gm"
+        class="com.google.android.gm.ConversationListActivityGmail"
+        shortcut="g" />
+    <bookmark
+        package="com.android.im"
+        class="com.android.im.app.LandingPage"
+        shortcut="i" />
+    <bookmark
+        package="com.android.calendar"
+        class="com.android.calendar.LaunchActivity"
+        shortcut="l" />
+<!--
+    <bookmark
+        package="com.google.android.apps.maps"
+        class="com.google.android.maps.MapsActivity"
+        shortcut="m" />
+-->
+    <bookmark
+        package="com.android.music"
+        class="com.android.music.MusicBrowserActivity"
+        shortcut="p" />
+    <bookmark
+        package="com.android.mms"
+        class="com.android.mms.ui.ConversationList"
+        shortcut="s" />
+</bookmarks>
diff --git a/services/java/com/android/server/status/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
similarity index 97%
rename from services/java/com/android/server/status/AnimatedImageView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 97df065..70d4d6a 100644
--- a/services/java/com/android/server/status/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.graphics.drawable.AnimationDrawable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
new file mode 100644
index 0000000..d89d093
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Telephony;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.TextView;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import com.android.internal.R;
+
+/**
+ * This widget display an analogic clock with two hands for hours and
+ * minutes.
+ */
+public class CarrierLabel extends TextView {
+    private boolean mAttached;
+
+    public CarrierLabel(Context context) {
+        this(context, null);
+    }
+
+    public CarrierLabel(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CarrierLabel(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        updateNetworkName(false, null, false, null);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (!mAttached) {
+            mAttached = true;
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
+            getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mAttached) {
+            getContext().unregisterReceiver(mIntentReceiver);
+            mAttached = false;
+        }
+    }
+
+    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
+                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
+                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
+            }
+        }
+    };
+
+    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+        if (false) {
+            Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
+        }
+        StringBuilder str = new StringBuilder();
+        boolean something = false;
+        if (showPlmn && plmn != null) {
+            str.append(plmn);
+            something = true;
+        }
+        if (showSpn && spn != null) {
+            if (something) {
+                str.append(' ');
+            }
+            str.append(spn);
+            something = true;
+        }
+        if (something) {
+            setText(str.toString());
+        } else {
+            setText(com.android.internal.R.string.lockscreen_carrier_default);
+        }
+    }
+
+    
+}
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java
new file mode 100644
index 0000000..9fc8df5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.format.DateFormat;
+import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import com.android.internal.R;
+
+/**
+ * This widget display an analogic clock with two hands for hours and
+ * minutes.
+ */
+public class Clock extends TextView {
+    private boolean mAttached;
+    private Calendar mCalendar;
+    private String mClockFormatString;
+    private SimpleDateFormat mClockFormat;
+
+    private static final int AM_PM_STYLE_NORMAL  = 0;
+    private static final int AM_PM_STYLE_SMALL   = 1;
+    private static final int AM_PM_STYLE_GONE    = 2;
+
+    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+
+    public Clock(Context context) {
+        this(context, null);
+    }
+
+    public Clock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public Clock(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (!mAttached) {
+            mAttached = true;
+            IntentFilter filter = new IntentFilter();
+
+            filter.addAction(Intent.ACTION_TIME_TICK);
+            filter.addAction(Intent.ACTION_TIME_CHANGED);
+            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+
+            getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+        }
+
+        // NOTE: It's safe to do these after registering the receiver since the receiver always runs
+        // in the main thread, therefore the receiver can't run before this method returns.
+
+        // The time zone may have changed while the receiver wasn't registered, so update the Time
+        mCalendar = Calendar.getInstance(TimeZone.getDefault());
+
+        // Make sure we update to the current time
+        updateClock();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mAttached) {
+            getContext().unregisterReceiver(mIntentReceiver);
+            mAttached = false;
+        }
+    }
+
+    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
+                String tz = intent.getStringExtra("time-zone");
+                mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
+                if (mClockFormat != null) {
+                    mClockFormat.setTimeZone(mCalendar.getTimeZone());
+                }
+            }
+            updateClock();
+        }
+    };
+
+    final void updateClock() {
+        mCalendar.setTimeInMillis(System.currentTimeMillis());
+        setText(getSmallTime());
+    }
+
+    private final CharSequence getSmallTime() {
+        Context context = getContext();
+        boolean b24 = DateFormat.is24HourFormat(context);
+        int res;
+
+        if (b24) {
+            res = R.string.twenty_four_hour_time_format;
+        } else {
+            res = R.string.twelve_hour_time_format;
+        }
+
+        final char MAGIC1 = '\uEF00';
+        final char MAGIC2 = '\uEF01';
+
+        SimpleDateFormat sdf;
+        String format = context.getString(res);
+        if (!format.equals(mClockFormatString)) {
+            /*
+             * Search for an unquoted "a" in the format string, so we can
+             * add dummy characters around it to let us find it again after
+             * formatting and change its size.
+             */
+            if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+                int a = -1;
+                boolean quoted = false;
+                for (int i = 0; i < format.length(); i++) {
+                    char c = format.charAt(i);
+
+                    if (c == '\'') {
+                        quoted = !quoted;
+                    }
+                    if (!quoted && c == 'a') {
+                        a = i;
+                        break;
+                    }
+                }
+
+                if (a >= 0) {
+                    // Move a back so any whitespace before AM/PM is also in the alternate size.
+                    final int b = a;
+                    while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
+                        a--;
+                    }
+                    format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
+                        + "a" + MAGIC2 + format.substring(b + 1);
+                }
+            }
+
+            mClockFormat = sdf = new SimpleDateFormat(format);
+            mClockFormatString = format;
+        } else {
+            sdf = mClockFormat;
+        }
+        String result = sdf.format(mCalendar.getTime());
+
+        if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+            int magic1 = result.indexOf(MAGIC1);
+            int magic2 = result.indexOf(MAGIC2);
+            if (magic1 >= 0 && magic2 > magic1) {
+                SpannableStringBuilder formatted = new SpannableStringBuilder(result);
+                if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
+                    formatted.delete(magic1, magic2+1);
+                } else {
+                    if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
+                        CharacterStyle style = new RelativeSizeSpan(0.7f);
+                        formatted.setSpan(style, magic1, magic2,
+                                          Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+                    }
+                    formatted.delete(magic2, magic2 + 1);
+                    formatted.delete(magic1, magic1 + 1);
+                }
+                return formatted;
+            }
+        }
+ 
+        return result;
+
+    }
+}
+
diff --git a/services/java/com/android/server/status/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
similarity index 94%
rename from services/java/com/android/server/status/CloseDragHandle.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
index ad1ac4d..0f6723e 100644
--- a/services/java/com/android/server/status/CloseDragHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -23,7 +23,7 @@
 
 
 public class CloseDragHandle extends LinearLayout {
-    StatusBarService mService;
+    PhoneStatusBarService mService;
 
     public CloseDragHandle(Context context, AttributeSet attrs) {
         super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
new file mode 100644
index 0000000..f9347b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+/**
+ * This class takes the functions from IStatusBar that come in on
+ * binder pool threads and posts messages to get them onto the main
+ * thread, and calls onto Callbacks.  It also takes care of
+ * coalescing these calls so they don't stack up.  For the calls
+ * are coalesced, note that they are all idempotent.
+ */
+class CommandQueue extends IStatusBar.Stub {
+    private static final String TAG = "StatusBar.CommandQueue";
+
+    private static final int MSG_MASK = 0xffff0000;
+    private static final int INDEX_MASK = 0x0000ffff;
+
+    private static final int MSG_ICON = 0x00010000;
+    private static final int OP_SET_ICON = 1;
+    private static final int OP_REMOVE_ICON = 2;
+
+    private static final int MSG_ADD_NOTIFICATION = 0x00020000;
+    private static final int MSG_UPDATE_NOTIFICATION = 0x00030000;
+    private static final int MSG_REMOVE_NOTIFICATION = 0x00040000;
+
+    private static final int MSG_DISABLE = 0x00050000;
+
+    private static final int MSG_SET_VISIBILITY = 0x00060000;
+    private static final int OP_EXPAND = 1;
+    private static final int OP_COLLAPSE = 2;
+
+    private StatusBarIconList mList;
+    private Callbacks mCallbacks;
+    private Handler mHandler = new H();
+
+    private class NotificationQueueEntry {
+        IBinder key;
+        StatusBarNotification notification;
+    }
+
+    /**
+     * These methods are called back on the main thread.
+     */
+    public interface Callbacks {
+        public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
+        public void updateIcon(String slot, int index, int viewIndex,
+                StatusBarIcon old, StatusBarIcon icon);
+        public void removeIcon(String slot, int index, int viewIndex);
+        public void addNotification(IBinder key, StatusBarNotification notification);
+        public void updateNotification(IBinder key, StatusBarNotification notification);
+        public void removeNotification(IBinder key);
+        public void disable(int state);
+        public void animateExpand();
+        public void animateCollapse();
+    }
+
+    public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
+        mCallbacks = callbacks;
+        mList = list;
+    }
+
+    public void setIcon(int index, StatusBarIcon icon) {
+        synchronized (mList) {
+            int what = MSG_ICON | index;
+            mHandler.removeMessages(what);
+            mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();
+        }
+    }
+
+    public void removeIcon(int index) {
+        synchronized (mList) {
+            int what = MSG_ICON | index;
+            mHandler.removeMessages(what);
+            mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget();
+        }
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        synchronized (mList) {
+            NotificationQueueEntry ne = new NotificationQueueEntry();
+            ne.key = key;
+            ne.notification = notification;
+            mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, ne).sendToTarget();
+        }
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        synchronized (mList) {
+            NotificationQueueEntry ne = new NotificationQueueEntry();
+            ne.key = key;
+            ne.notification = notification;
+            mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, ne).sendToTarget();
+        }
+    }
+
+    public void removeNotification(IBinder key) {
+        synchronized (mList) {
+            mHandler.obtainMessage(MSG_REMOVE_NOTIFICATION, 0, 0, key).sendToTarget();
+        }
+    }
+
+    public void disable(int state) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_DISABLE);
+            mHandler.obtainMessage(MSG_DISABLE, state, 0, null).sendToTarget();
+        }
+    }
+
+    public void animateExpand() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SET_VISIBILITY);
+            mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_EXPAND, 0, null).sendToTarget();
+        }
+    }
+
+    public void animateCollapse() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SET_VISIBILITY);
+            mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, 0, null).sendToTarget();
+        }
+    }
+
+    private final class H extends Handler {
+        public void handleMessage(Message msg) {
+            final int what = msg.what & MSG_MASK;
+            switch (what) {
+                case MSG_ICON: {
+                    final int index = msg.what & INDEX_MASK;
+                    final int viewIndex = mList.getViewIndex(index);
+                    switch (msg.arg1) {
+                        case OP_SET_ICON: {
+                            StatusBarIcon icon = (StatusBarIcon)msg.obj;
+                            StatusBarIcon old = mList.getIcon(index);
+                            if (old == null) {
+                                mList.setIcon(index, icon);
+                                mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon);
+                            } else {
+                                mList.setIcon(index, icon);
+                                mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,
+                                        old, icon);
+                            }
+                            break;
+                        }
+                        case OP_REMOVE_ICON:
+                            mList.removeIcon(index);
+                            mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex);
+                            break;
+                    }
+                    break;
+                }
+                case MSG_ADD_NOTIFICATION: {
+                    final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
+                    mCallbacks.addNotification(ne.key, ne.notification);
+                    break;
+                }
+                case MSG_UPDATE_NOTIFICATION: {
+                    final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
+                    mCallbacks.updateNotification(ne.key, ne.notification);
+                    break;
+                }
+                case MSG_REMOVE_NOTIFICATION: {
+                    mCallbacks.removeNotification((IBinder)msg.obj);
+                    break;
+                }
+                case MSG_DISABLE:
+                    mCallbacks.disable(msg.arg1);
+                    break;
+                case MSG_SET_VISIBILITY:
+                    if (msg.arg1 == OP_EXPAND) {
+                        mCallbacks.animateExpand();
+                    } else {
+                        mCallbacks.animateCollapse();
+                    }
+            }
+        }
+    }
+}
+
diff --git a/services/java/com/android/server/status/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
similarity index 98%
rename from services/java/com/android/server/status/DateView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
index c04fb45..e6d3a7e 100644
--- a/services/java/com/android/server/status/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/services/java/com/android/server/status/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
similarity index 84%
rename from services/java/com/android/server/status/ExpandedView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
index cb37f90..c5b901f 100644
--- a/services/java/com/android/server/status/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -27,7 +27,7 @@
 
 
 public class ExpandedView extends LinearLayout {
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     int mPrevHeight = -1;
 
     public ExpandedView(Context context, AttributeSet attrs) {
@@ -50,9 +50,10 @@
          super.onLayout(changed, left, top, right, bottom);
          int height = bottom - top;
          if (height != mPrevHeight) {
-             //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight + " new=" + height);
+             //Slog.d(PhoneStatusBarService.TAG, "height changed old=" + mPrevHeight
+             //     + " new=" + height);
              mPrevHeight = height;
-             mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+             mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
          }
      }
 }
diff --git a/services/java/com/android/server/status/FixedSizeDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
similarity index 97%
rename from services/java/com/android/server/status/FixedSizeDrawable.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
index dbfcb2c..eb22b61 100644
--- a/services/java/com/android/server/status/FixedSizeDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
diff --git a/services/java/com/android/server/status/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
similarity index 80%
rename from services/java/com/android/server/status/IconMerger.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
index aa702ae..027bed4a 100644
--- a/services/java/com/android/server/status/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
@@ -14,23 +14,39 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.os.Handler;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.View;
 import android.widget.LinearLayout;
 
+import com.android.systemui.R;
+
 
 public class IconMerger extends LinearLayout {
-    StatusBarService service;
-    StatusBarIcon moreIcon;
+    private static final String TAG = "IconMerger";
+
+    private StatusBarIconView mMoreView;
 
     public IconMerger(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    public void addMoreView(StatusBarIconView v, LinearLayout.LayoutParams lp) {
+        super.addView(v, lp);
+        mMoreView = v;
+    }
+
+    public void addView(StatusBarIconView v, int index, LinearLayout.LayoutParams lp) {
+        if (index == 0) {
+            throw new RuntimeException("Attempt to put view before the more view: " + v);
+        }
+        super.addView(v, index, lp);
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
@@ -50,13 +66,12 @@
         }
 
         // find the first visible one that isn't the more icon
-        View moreView = null;
+        final StatusBarIconView moreView = mMoreView;
         int fitLeft = -1;
         int startIndex = -1;
         for (i=0; i<N; i++) {
             final View child = getChildAt(i);
-            if (com.android.internal.R.drawable.stat_notify_more == child.getId()) {
-                moreView = child;
+            if (child == moreView) {
                 startIndex = i+1;
             }
             else if (child.getVisibility() != GONE) {
@@ -66,7 +81,11 @@
         }
 
         if (moreView == null || startIndex < 0) {
-            throw new RuntimeException("Status Bar / IconMerger moreView == null");
+            return;
+            /*
+            throw new RuntimeException("Status Bar / IconMerger moreView == " + moreView
+                    + " startIndex=" + startIndex);
+            */
         }
         
         // if it fits without the more icon, then hide the more icon and update fitLeft
@@ -84,14 +103,14 @@
         int breakingPoint = fitLeft + extra + adjust;
         int number = 0;
         for (i=startIndex; i<N; i++) {
-            final View child = getChildAt(i);
+            final StatusBarIconView child = (StatusBarIconView)getChildAt(i);
             if (child.getVisibility() != GONE) {
                 int childLeft = child.getLeft();
                 int childRight = child.getRight();
                 if (childLeft < breakingPoint) {
                     // hide this one
                     child.layout(0, child.getTop(), 0, child.getBottom());
-                    int n = this.service.getIconNumberForView(child);
+                    int n = child.getStatusBarIcon().number;
                     if (n == 0) {
                         number += 1;
                     } else if (n > 0) {
@@ -115,7 +134,7 @@
         // and provide the value later.  We're the only one changing this value show it
         // should be ordered correctly.
         if (false) {
-            this.moreIcon.update(number);
+            // TODO this.moreIcon.update(number);
         } else {
             mBugWorkaroundNumber = number;
             mBugWorkaroundHandler.post(mBugWorkaroundRunnable);
@@ -126,8 +145,10 @@
     private Handler mBugWorkaroundHandler = new Handler();
     private Runnable mBugWorkaroundRunnable = new Runnable() {
         public void run() {
+            /* TODO
             IconMerger.this.moreIcon.update(mBugWorkaroundNumber);
             IconMerger.this.moreIcon.view.invalidate();
+            */
         }
     };
 }
diff --git a/services/java/com/android/server/status/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
similarity index 67%
copy from services/java/com/android/server/status/NotificationLinearLayout.java
copy to packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
index 2fdf956..1e89624 100644
--- a/services/java/com/android/server/status/NotificationLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
@@ -14,16 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.widget.LinearLayout;
+import android.util.Slog;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
 
+public class LatestItemView extends FrameLayout {
 
-public class NotificationLinearLayout extends LinearLayout {
-    public NotificationLinearLayout(Context context, AttributeSet attrs) {
+    public LatestItemView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
-}
 
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        return onTouchEvent(ev);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
new file mode 100644
index 0000000..7a82267
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.app.Notification;
+import android.os.IBinder;
+import android.view.View;
+
+import com.android.internal.statusbar.StatusBarNotification;
+
+import java.util.ArrayList;
+
+/**
+ * The list of currently displaying notifications.
+ */
+public class NotificationData {
+    public static final class Entry {
+        public IBinder key;
+        public StatusBarNotification notification;
+        public StatusBarIconView icon;
+        public View row; // the outer expanded view
+        public View content; // takes the click events and sends the PendingIntent
+        public View expanded; // the inflated RemoteViews
+    }
+    private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
+
+    public int size() {
+        return mEntries.size();
+    }
+
+    public Entry getEntryAt(int index) {
+        return mEntries.get(index);
+    }
+
+    public int findEntry(IBinder key) {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.key == key) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public int add(IBinder key, StatusBarNotification notification, View row, View content,
+            View expanded, StatusBarIconView icon) {
+        Entry entry = new Entry();
+        entry.key = key;
+        entry.notification = notification;
+        entry.row = row;
+        entry.content = content;
+        entry.expanded = expanded;
+        entry.icon = icon;
+        final int index = chooseIndex(notification.notification.when);
+        mEntries.add(index, entry);
+        return index;
+    }
+
+    public Entry remove(IBinder key) {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.key == key) {
+                mEntries.remove(i);
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    private int chooseIndex(final long when) {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.notification.notification.when > when) {
+                return i;
+            }
+        }
+        return N;
+    }
+
+    /**
+     * Return whether there are any visible items (i.e. items without an error).
+     */
+    public boolean hasVisibleItems() {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.expanded != null) { // the view successfully inflated
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return whether there are any clearable items (that aren't errors).
+     */
+    public boolean hasClearableItems() {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.expanded != null) { // the view successfully inflated
+                if ((entry.notification.notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/services/java/com/android/server/status/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
similarity index 95%
rename from services/java/com/android/server/status/NotificationLinearLayout.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
index 2fdf956..8105352 100644
--- a/services/java/com/android/server/status/NotificationLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
new file mode 100644
index 0000000..e9ae69a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -0,0 +1,1419 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import android.app.ActivityManagerNative;
+import android.app.Dialog;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.FrameLayout;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.StatusBarPolicy;
+
+public class PhoneStatusBarService extends StatusBarService {
+    static final String TAG = "PhoneStatusBarService";
+    static final boolean SPEW = false;
+
+    public static final String ACTION_STATUSBAR_START
+            = "com.android.internal.policy.statusbar.START";
+
+    static final int EXPANDED_LEAVE_ALONE = -10000;
+    static final int EXPANDED_FULL_OPEN = -10001;
+
+    private static final int MSG_ANIMATE = 1000;
+    private static final int MSG_ANIMATE_REVEAL = 1001;
+
+    public interface NotificationCallbacks {
+        void onSetDisabled(int status);
+        void onClearAll();
+        void onNotificationClick(String pkg, String tag, int id);
+        void onPanelRevealed();
+    }
+
+    private class ExpandedDialog extends Dialog {
+        ExpandedDialog(Context context) {
+            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+            switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_BACK:
+                if (!down) {
+                    animateCollapse();
+                }
+                return true;
+            }
+            return super.dispatchKeyEvent(event);
+        }
+    }
+
+    StatusBarPolicy mIconPolicy;
+    
+    int mHeight;
+    int mIconWidth;
+
+    Display mDisplay;
+    StatusBarView mStatusBarView;
+    int mPixelFormat;
+    H mHandler = new H();
+    Object mQueueLock = new Object();
+    
+    // icons
+    String[] mRightIconSlots;
+    LinearLayout mIcons;
+    IconMerger mNotificationIcons;
+    LinearLayout mStatusIcons;
+
+    // expanded notifications
+    Dialog mExpandedDialog;
+    ExpandedView mExpandedView;
+    WindowManager.LayoutParams mExpandedParams;
+    ScrollView mScrollView;
+    View mNotificationLinearLayout;
+    View mExpandedContents;
+    // top bar
+    TextView mNoNotificationsTitle;
+    TextView mClearButton;
+    // drag bar
+    CloseDragHandle mCloseView;
+    // ongoing
+    NotificationData mOngoing = new NotificationData();
+    TextView mOngoingTitle;
+    LinearLayout mOngoingItems;
+    // latest
+    NotificationData mLatest = new NotificationData();
+    TextView mLatestTitle;
+    LinearLayout mLatestItems;
+    // position
+    int[] mPositionTmp = new int[2];
+    boolean mExpanded;
+    boolean mExpandedVisible;
+
+    // the date view
+    DateView mDateView;
+
+    // the tracker view
+    TrackingView mTrackingView;
+    WindowManager.LayoutParams mTrackingParams;
+    int mTrackingPosition; // the position of the top of the tracking view.
+
+    // ticker
+    private Ticker mTicker;
+    private View mTickerView;
+    private boolean mTicking;
+    
+    // Tracking finger for opening/closing.
+    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
+    boolean mTracking;
+    VelocityTracker mVelocityTracker;
+    
+    static final int ANIM_FRAME_DURATION = (1000/60);
+    
+    boolean mAnimating;
+    long mCurAnimationTime;
+    float mDisplayHeight;
+    float mAnimY;
+    float mAnimVel;
+    float mAnimAccel;
+    long mAnimLastTime;
+    boolean mAnimatingReveal = false;
+    int mViewDelta;
+    int[] mAbsPos = new int[2];
+    
+    // for disabling the status bar
+    int mDisabled = 0;
+
+    /**
+     * Construct the service, add the status bar view to the window manager
+     */
+    @Override
+    public void onCreate() {
+        // First set up our views and stuff.
+        mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        makeStatusBarView(this);
+
+        // Next, call super.onCreate(), which will populate our views.
+        super.onCreate();
+
+        // Lastly, call to the icon policy to install/update all the icons.
+        mIconPolicy = new StatusBarPolicy(this);
+    }
+
+    // ================================================================================
+    // Constructing the view
+    // ================================================================================
+    private void makeStatusBarView(Context context) {
+        Resources res = context.getResources();
+        mRightIconSlots = res.getStringArray(R.array.status_bar_icon_order);
+
+        mHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+        mIconWidth = mHeight;
+
+        ExpandedView expanded = (ExpandedView)View.inflate(context,
+                R.layout.status_bar_expanded, null);
+        expanded.mService = this;
+        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
+        sb.mService = this;
+
+        // figure out which pixel-format to use for the status bar.
+        mPixelFormat = PixelFormat.TRANSLUCENT;
+        Drawable bg = sb.getBackground();
+        if (bg != null) {
+            mPixelFormat = bg.getOpacity();
+        }
+
+        mStatusBarView = sb;
+        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
+        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
+        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
+        mTickerView = sb.findViewById(R.id.ticker);
+        mDateView = (DateView)sb.findViewById(R.id.date);
+
+        mExpandedDialog = new ExpandedDialog(context);
+        mExpandedView = expanded;
+        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
+        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
+        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
+        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
+        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
+        mClearButton.setOnClickListener(mClearButtonListener);
+        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
+        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
+
+        mOngoingTitle.setVisibility(View.GONE);
+        mLatestTitle.setVisibility(View.GONE);
+        
+        mTicker = new MyTicker(context, sb);
+
+        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
+        tickerView.mTicker = mTicker;
+
+        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
+        mTrackingView.mService = this;
+        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
+        mCloseView.mService = this;
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        // the more notifications icon
+        StatusBarIconView moreView = new StatusBarIconView(this, "more");
+        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
+        mNotificationIcons.addMoreView(moreView,
+                new LinearLayout.LayoutParams(mIconWidth, mHeight));
+
+        // set the inital view visibility
+        setAreThereNotifications();
+        mDateView.setVisibility(View.INVISIBLE);
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        context.registerReceiver(mBroadcastReceiver, filter);
+    }
+
+    @Override
+    protected void addStatusBarView() {
+        final StatusBarView view = mStatusBarView;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                mHeight,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
+                PixelFormat.RGBX_8888);
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBar");
+        // TODO lp.windowAnimations = R.style.Animation_StatusBar;
+
+        WindowManagerImpl.getDefault().addView(view, lp);
+    }
+
+    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " icon=" + icon);
+        StatusBarIconView view = new StatusBarIconView(this, slot);
+        view.set(icon);
+        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconWidth, mHeight));
+    }
+
+    public void updateIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " old=" + old + " icon=" + icon);
+        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
+        view.set(icon);
+    }
+
+    public void removeIcon(String slot, int index, int viewIndex) {
+        Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
+        mStatusIcons.removeViewAt(viewIndex);
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        addNotificationViews(key, notification);
+
+        // show the ticker
+        tick(notification);
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
+
+        NotificationData oldList;
+        int oldIndex = mOngoing.findEntry(key);
+        if (oldIndex >= 0) {
+            oldList = mOngoing;
+        } else {
+            oldIndex = mLatest.findEntry(key);
+            if (oldIndex < 0) {
+                Slog.w(TAG, "updateNotification for unknown key: " + key);
+                return;
+            }
+            oldList = mLatest;
+        }
+        final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
+        final StatusBarNotification oldNotification = oldEntry.notification;
+        final RemoteViews oldContentView = oldNotification.notification.contentView;
+
+        final RemoteViews contentView = notification.notification.contentView;
+
+        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
+        // didn't change.
+        if (notification.notification.when == oldNotification.notification.when
+                && notification.isOngoing() == oldNotification.isOngoing()
+                && oldEntry.expanded != null
+                && contentView != null && oldContentView != null
+                && contentView.getPackage() != null
+                && oldContentView.getPackage() != null
+                && oldContentView.getPackage().equals(contentView.getPackage())
+                && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+            Slog.d(TAG, "reusing notification");
+            oldEntry.notification = notification;
+            try {
+                // Reapply the RemoteViews
+                contentView.reapply(this, oldEntry.content);
+                // update the contentIntent
+                final PendingIntent contentIntent = notification.notification.contentIntent;
+                if (contentIntent != null) {
+                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
+                                notification.pkg, notification.tag, notification.id));
+                }
+            }
+            catch (RuntimeException e) {
+                // It failed to add cleanly.  Log, and remove the view from the panel.
+                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+                removeNotificationViews(key);
+                addNotificationViews(key, notification);
+            }
+            // Update the icon.
+            oldEntry.icon.set(new StatusBarIcon(notification.pkg, notification.notification.icon,
+                    notification.notification.iconLevel, notification.notification.number));
+        } else {
+            Slog.d(TAG, "not reusing notification");
+            removeNotificationViews(key);
+            addNotificationViews(key, notification);
+        }
+
+        // Restart the ticker if it's still running
+        tick(notification);
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void removeNotification(IBinder key) {
+        Slog.d(TAG, "removeNotification key=" + key);
+        StatusBarNotification old = removeNotificationViews(key);
+
+        if (old != null) {
+            // Cancel the ticker if it's still running
+            mTicker.removeEntry(old);
+
+            // Recalculate the position of the sliding windows and the titles.
+            setAreThereNotifications();
+            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        }
+    }
+
+    private int chooseIconIndex(boolean isOngoing, int viewIndex) {
+        final int latestSize = mLatest.size();
+        if (isOngoing) {
+            return latestSize + (mOngoing.size() - viewIndex);
+        } else {
+            return latestSize - viewIndex;
+        }
+    }
+
+    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
+        Notification n = notification.notification;
+        RemoteViews remoteViews = n.contentView;
+        if (remoteViews == null) {
+            return null;
+        }
+
+        // create the row view
+        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event,
+                parent, false);
+
+        // bind the click event to the content area
+        ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content);
+        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        content.setOnFocusChangeListener(mFocusChangeListener);
+        PendingIntent contentIntent = n.contentIntent;
+        if (contentIntent != null) {
+            content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
+                        notification.tag, notification.id));
+        }
+
+        View expanded = null;
+        Exception exception = null;
+        try {
+            expanded = remoteViews.apply(this, content);
+        }
+        catch (RuntimeException e) {
+            exception = e;
+        }
+        if (expanded == null) {
+            Slog.e(TAG, "couldn't inflate view for package " + notification.pkg, exception);
+            row.setVisibility(View.GONE);
+        } else {
+            content.addView(expanded);
+            row.setDrawingCacheEnabled(true);
+        }
+
+        return new View[] { row, content, expanded };
+    }
+
+    void addNotificationViews(IBinder key, StatusBarNotification notification) {
+        NotificationData list;
+        ViewGroup parent;
+        final boolean isOngoing = notification.isOngoing();
+        if (isOngoing) {
+            list = mOngoing;
+            parent = mOngoingItems;
+        } else {
+            list = mLatest;
+            parent = mLatestItems;
+        }
+        // Construct the expanded view.
+        final View[] views = makeNotificationView(notification, parent);
+        final View row = views[0];
+        final View content = views[1];
+        final View expanded = views[2];
+        // Construct the icon.
+        StatusBarIconView iconView = new StatusBarIconView(this,
+                notification.pkg + "/0x" + Integer.toHexString(notification.id));
+        iconView.set(new StatusBarIcon(notification.pkg, notification.notification.icon,
+                    notification.notification.iconLevel, notification.notification.number));
+        // Add the expanded view.
+        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
+        parent.addView(row, viewIndex);
+        // Add the icon.
+        final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
+        mNotificationIcons.addView(iconView, iconIndex,
+                new LinearLayout.LayoutParams(mIconWidth, mHeight));
+    }
+
+    StatusBarNotification removeNotificationViews(IBinder key) {
+        NotificationData.Entry entry = mOngoing.remove(key);
+        if (entry == null) {
+            entry = mLatest.remove(key);
+            if (entry == null) {
+                Slog.w(TAG, "removeNotification for unknown key: " + key);
+                return null;
+            }
+        }
+        // Remove the expanded view.
+        ((ViewGroup)entry.row.getParent()).removeView(entry.row);
+        // Remove the icon.
+        ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
+
+        return entry.notification;
+    }
+
+    private void setAreThereNotifications() {
+        boolean ongoing = mOngoing.hasVisibleItems();
+        boolean latest = mLatest.hasVisibleItems();
+
+        // (no ongoing notifications are clearable)
+        if (mLatest.hasClearableItems()) {
+            mClearButton.setVisibility(View.VISIBLE);
+        } else {
+            mClearButton.setVisibility(View.INVISIBLE);
+        }
+
+        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
+        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
+
+        if (ongoing || latest) {
+            mNoNotificationsTitle.setVisibility(View.GONE);
+        } else {
+            mNoNotificationsTitle.setVisibility(View.VISIBLE);
+        }
+    }
+
+
+    /**
+     * State is one or more of the DISABLE constants from StatusBarManager.
+     */
+    public void disable(int state) {
+        final int old = mDisabled;
+        final int diff = state ^ old;
+        mDisabled = state;
+
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+                mTicker.halt();
+            }
+        }
+    }
+
+    /**
+     * All changes to the status bar and notifications funnel through here and are batched.
+     */
+    private class H extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_ANIMATE:
+                    doAnimation();
+                    break;
+                case MSG_ANIMATE_REVEAL:
+                    doRevealAnimation();
+                    break;
+            }
+        }
+    }
+
+    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
+        public void onFocusChange(View v, boolean hasFocus) {
+            // Because 'v' is a ViewGroup, all its children will be (un)selected
+            // too, which allows marqueeing to work.
+            v.setSelected(hasFocus);
+        }
+    };
+
+    private void makeExpandedVisible() {
+        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+        if (mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = true;
+        visibilityChanged(true);
+        
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mExpandedView.requestFocus(View.FOCUS_FORWARD);
+        mTrackingView.setVisibility(View.VISIBLE);
+        
+        if (!mTicking) {
+            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+    }
+    
+    public void animateExpand() {
+        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        prepareTracking(0, true);
+        performFling(0, 2000.0f, true);
+    }
+    
+    public void animateCollapse() {
+        if (SPEW) {
+            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+                    + " mExpandedVisible=" + mExpandedVisible
+                    + " mExpanded=" + mExpanded
+                    + " mAnimating=" + mAnimating
+                    + " mAnimY=" + mAnimY
+                    + " mAnimVel=" + mAnimVel);
+        }
+        
+        if (!mExpandedVisible) {
+            return;
+        }
+
+        int y;
+        if (mAnimating) {
+            y = (int)mAnimY;
+        } else {
+            y = mDisplay.getHeight()-1;
+        }
+        // Let the fling think that we're open so it goes in the right direction
+        // and doesn't try to re-open the windowshade.
+        mExpanded = true;
+        prepareTracking(y, false);
+        performFling(y, -2000.0f, true);
+    }
+    
+    void performExpand() {
+        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        mExpanded = true;
+        makeExpandedVisible();
+        updateExpandedViewPos(EXPANDED_FULL_OPEN);
+
+        if (false) postStartTracing();
+    }
+
+    void performCollapse() {
+        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+                + " mExpandedVisible=" + mExpandedVisible);
+        
+        if (!mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = false;
+        visibilityChanged(false);
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mTrackingView.setVisibility(View.GONE);
+
+        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
+        
+        if (!mExpanded) {
+            return;
+        }
+        mExpanded = false;
+    }
+
+    void doAnimation() {
+        if (mAnimating) {
+            if (SPEW) Slog.d(TAG, "doAnimation");
+            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
+            incrementAnim();
+            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
+            if (mAnimY >= mDisplay.getHeight()-1) {
+                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
+                mAnimating = false;
+                updateExpandedViewPos(EXPANDED_FULL_OPEN);
+                performExpand();
+            }
+            else if (mAnimY < mStatusBarView.getHeight()) {
+                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
+                mAnimating = false;
+                updateExpandedViewPos(0);
+                performCollapse();
+            }
+            else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+            }
+        }
+    }
+
+    void stopTracking() {
+        mTracking = false;
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+    }
+
+    void incrementAnim() {
+        long now = SystemClock.uptimeMillis();
+        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
+        final float y = mAnimY;
+        final float v = mAnimVel;                                   // px/s
+        final float a = mAnimAccel;                                 // px/s/s
+        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
+        mAnimVel = v + (a*t);                                       // px/s
+        mAnimLastTime = now;                                        // ms
+        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
+        //        + " mAnimAccel=" + mAnimAccel);
+    }
+
+    void doRevealAnimation() {
+        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
+        if (mAnimatingReveal && mAnimating && mAnimY < h) {
+            incrementAnim();
+            if (mAnimY >= h) {
+                mAnimY = h;
+                updateExpandedViewPos((int)mAnimY);
+            } else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                        mCurAnimationTime);
+            }
+        }
+    }
+    
+    void prepareTracking(int y, boolean opening) {
+        mTracking = true;
+        mVelocityTracker = VelocityTracker.obtain();
+        if (opening) {
+            mAnimAccel = 2000.0f;
+            mAnimVel = 200;
+            mAnimY = mStatusBarView.getHeight();
+            updateExpandedViewPos((int)mAnimY);
+            mAnimating = true;
+            mAnimatingReveal = true;
+            mHandler.removeMessages(MSG_ANIMATE);
+            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+            long now = SystemClock.uptimeMillis();
+            mAnimLastTime = now;
+            mCurAnimationTime = now + ANIM_FRAME_DURATION;
+            mAnimating = true;
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                    mCurAnimationTime);
+            makeExpandedVisible();
+        } else {
+            // it's open, close it?
+            if (mAnimating) {
+                mAnimating = false;
+                mHandler.removeMessages(MSG_ANIMATE);
+            }
+            updateExpandedViewPos(y + mViewDelta);
+        }
+    }
+    
+    void performFling(int y, float vel, boolean always) {
+        mAnimatingReveal = false;
+        mDisplayHeight = mDisplay.getHeight();
+
+        mAnimY = y;
+        mAnimVel = vel;
+
+        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
+
+        if (mExpanded) {
+            if (!always && (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+                // We are expanded, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the expanded position.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are expanded and are now going to animate away.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        } else {
+            if (always || (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+                // We are collapsed, and they moved enough to allow us to
+                // expand.  Animate in the notifications.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are collapsed, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the collapsed position.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        }
+        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
+        //        + " mAnimAccel=" + mAnimAccel);
+
+        long now = SystemClock.uptimeMillis();
+        mAnimLastTime = now;
+        mCurAnimationTime = now + ANIM_FRAME_DURATION;
+        mAnimating = true;
+        mHandler.removeMessages(MSG_ANIMATE);
+        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+        stopTracking();
+    }
+    
+    boolean interceptTouchEvent(MotionEvent event) {
+        if (SPEW) {
+            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+                + mDisabled);
+        }
+
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return false;
+        }
+        
+        final int statusBarSize = mStatusBarView.getHeight();
+        final int hitSize = statusBarSize*2;
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            final int y = (int)event.getRawY();
+
+            if (!mExpanded) {
+                mViewDelta = statusBarSize - y;
+            } else {
+                mTrackingView.getLocationOnScreen(mAbsPos);
+                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
+            }
+            if ((!mExpanded && y < hitSize) ||
+                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+
+                // We drop events at the edge of the screen to make the windowshade come
+                // down by accident less, especially when pushing open a device with a keyboard
+                // that rotates (like g1 and droid)
+                int x = (int)event.getRawX();
+                final int edgeBorder = mEdgeBorder;
+                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
+                    mVelocityTracker.addMovement(event);
+                }
+            }
+        } else if (mTracking) {
+            mVelocityTracker.addMovement(event);
+            final int minY = statusBarSize + mCloseView.getHeight();
+            if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                int y = (int)event.getRawY();
+                if (mAnimatingReveal && y < minY) {
+                    // nothing
+                } else  {
+                    mAnimatingReveal = false;
+                    updateExpandedViewPos(y + mViewDelta);
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                mVelocityTracker.computeCurrentVelocity(1000);
+
+                float yVel = mVelocityTracker.getYVelocity();
+                boolean negative = yVel < 0;
+
+                float xVel = mVelocityTracker.getXVelocity();
+                if (xVel < 0) {
+                    xVel = -xVel;
+                }
+                if (xVel > 150.0f) {
+                    xVel = 150.0f; // limit how much we care about the x axis
+                }
+
+                float vel = (float)Math.hypot(yVel, xVel);
+                if (negative) {
+                    vel = -vel;
+                }
+                
+                performFling((int)event.getRawY(), vel, false);
+            }
+            
+        }
+        return false;
+    }
+
+    private class Launcher implements View.OnClickListener {
+        private PendingIntent mIntent;
+        private String mPkg;
+        private String mTag;
+        private int mId;
+
+        Launcher(PendingIntent intent, String pkg, String tag, int id) {
+            mIntent = intent;
+            mPkg = pkg;
+            mTag = tag;
+            mId = id;
+        }
+
+        public void onClick(View v) {
+            try {
+                // The intent we are sending is for the application, which
+                // won't have permission to immediately start an activity after
+                // the user switches to home.  We know it is safe to do at this
+                // point, so make sure new activity switches are now allowed.
+                ActivityManagerNative.getDefault().resumeAppSwitches();
+            } catch (RemoteException e) {
+            }
+            int[] pos = new int[2];
+            v.getLocationOnScreen(pos);
+            Intent overlay = new Intent();
+            overlay.setSourceBounds(
+                    new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+            try {
+                mIntent.send(PhoneStatusBarService.this, 0, overlay);
+            } catch (PendingIntent.CanceledException e) {
+                // the stack trace isn't very helpful here.  Just log the exception message.
+                Slog.w(TAG, "Sending contentIntent failed: " + e);
+            }
+            try {
+                mBarService.onNotificationClick(mPkg, mTag, mId);
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+            animateCollapse();
+        }
+    }
+
+    private void tick(StatusBarNotification n) {
+        // Show the ticker if one is requested. Also don't do this
+        // until status bar window is attached to the window manager,
+        // because...  well, what's the point otherwise?  And trying to
+        // run a ticker without being attached will crash!
+        if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
+            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
+                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+                mTicker.addEntry(n);
+            }
+        }
+    }
+
+    private class MyTicker extends Ticker {
+        MyTicker(Context context, StatusBarView sb) {
+            super(context, sb);
+        }
+        
+        @Override
+        void tickerStarting() {
+            mTicking = true;
+            mIcons.setVisibility(View.GONE);
+            mTickerView.setVisibility(View.VISIBLE);
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
+            if (mExpandedVisible) {
+                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
+            }
+        }
+
+        @Override
+        void tickerDone() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
+            }
+        }
+
+        void tickerHalting() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+            }
+        }
+    }
+
+    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
+        public void onAnimationEnd(Animation animation) {
+            mTicking = false;
+        }
+        public void onAnimationRepeat(Animation animation) {
+        }
+        public void onAnimationStart(Animation animation) {
+        }
+    };
+
+    private Animation loadAnim(int id, Animation.AnimationListener listener) {
+        Animation anim = AnimationUtils.loadAnimation(PhoneStatusBarService.this, id);
+        if (listener != null) {
+            anim.setAnimationListener(listener);
+        }
+        return anim;
+    }
+
+    public String viewInfo(View v) {
+        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
+                + " " + v.getWidth() + "x" + v.getHeight() + ")";
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump StatusBar from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+        
+        synchronized (mQueueLock) {
+            pw.println("Current Status Bar state:");
+            pw.println("  mExpanded=" + mExpanded
+                    + ", mExpandedVisible=" + mExpandedVisible);
+            pw.println("  mTicking=" + mTicking);
+            pw.println("  mTracking=" + mTracking);
+            pw.println("  mAnimating=" + mAnimating
+                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
+                    + ", mAnimAccel=" + mAnimAccel);
+            pw.println("  mCurAnimationTime=" + mCurAnimationTime
+                    + " mAnimLastTime=" + mAnimLastTime);
+            pw.println("  mDisplayHeight=" + mDisplayHeight
+                    + " mAnimatingReveal=" + mAnimatingReveal
+                    + " mViewDelta=" + mViewDelta);
+            pw.println("  mDisplayHeight=" + mDisplayHeight);
+            pw.println("  mExpandedParams: " + mExpandedParams);
+            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
+            pw.println("  mExpandedDialog: " + mExpandedDialog);
+            pw.println("  mTrackingParams: " + mTrackingParams);
+            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
+            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
+            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
+            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
+            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
+            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
+            pw.println("  mCloseView: " + viewInfo(mCloseView));
+            pw.println("  mTickerView: " + viewInfo(mTickerView));
+            pw.println("  mScrollView: " + viewInfo(mScrollView)
+                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
+            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
+        }
+        /*
+        synchronized (mNotificationData) {
+            int N = mNotificationData.ongoingCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getOngoing(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+            N = mNotificationData.latestCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getLatest(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+        }
+        */
+        
+        if (false) {
+            pw.println("see the logcat for a dump of the views we have created.");
+            // must happen on ui thread
+            mHandler.post(new Runnable() {
+                    public void run() {
+                        mStatusBarView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mStatusBarView.getWidth() + "x"
+                                + mStatusBarView.getHeight());
+                        mStatusBarView.debug();
+
+                        mExpandedView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mExpandedView.getWidth() + "x"
+                                + mExpandedView.getHeight());
+                        mExpandedView.debug();
+
+                        mTrackingView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mTrackingView.getWidth() + "x"
+                                + mTrackingView.getHeight());
+                        mTrackingView.debug();
+                    }
+                });
+        }
+    }
+
+    void onBarViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Tracking View --------------
+        pixelFormat = PixelFormat.RGBX_8888;
+        bg = mTrackingView.getBackground();
+        if (bg != null) {
+            pixelFormat = bg.getOpacity();
+        }
+
+        lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                pixelFormat);
+//        lp.token = mStatusBarView.getWindowToken();
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("TrackingView");
+        lp.y = mTrackingPosition;
+        mTrackingParams = lp;
+
+        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
+    }
+
+    void onTrackingViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Expanded View --------------
+        pixelFormat = PixelFormat.TRANSLUCENT;
+
+        final int disph = mDisplay.getHeight();
+        lp = mExpandedDialog.getWindow().getAttributes();
+        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        lp.height = getExpandedHeight();
+        lp.x = 0;
+        mTrackingPosition = lp.y = -disph; // sufficiently large negative
+        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_DITHER
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        lp.format = pixelFormat;
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBarExpanded");
+        mExpandedDialog.getWindow().setAttributes(lp);
+        mExpandedDialog.getWindow().setFormat(pixelFormat);
+        mExpandedParams = lp;
+
+        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mExpandedDialog.setContentView(mExpandedView,
+                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                           ViewGroup.LayoutParams.MATCH_PARENT));
+        mExpandedDialog.getWindow().setBackgroundDrawable(null);
+        mExpandedDialog.show();
+        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
+    }
+
+    void setDateViewVisibility(boolean visible, int anim) {
+        mDateView.setUpdates(visible);
+        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        mDateView.startAnimation(loadAnim(anim, null));
+    }
+
+    void setNotificationIconVisibility(boolean visible, int anim) {
+        int old = mNotificationIcons.getVisibility();
+        int v = visible ? View.VISIBLE : View.INVISIBLE;
+        if (old != v) {
+            mNotificationIcons.setVisibility(v);
+            mNotificationIcons.startAnimation(loadAnim(anim, null));
+        }
+    }
+
+    void updateExpandedViewPos(int expandedPosition) {
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition);
+        }
+
+        int h = mStatusBarView.getHeight();
+        int disph = mDisplay.getHeight();
+
+        // If the expanded view is not visible, make sure they're still off screen.
+        // Maybe the view was resized.
+        if (!mExpandedVisible) {
+            if (mTrackingView != null) {
+                mTrackingPosition = -disph;
+                if (mTrackingParams != null) {
+                    mTrackingParams.y = mTrackingPosition;
+                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+                }
+            }
+            if (mExpandedParams != null) {
+                mExpandedParams.y = -disph;
+                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+            }
+            return;
+        }
+
+        // tracking view...
+        int pos;
+        if (expandedPosition == EXPANDED_FULL_OPEN) {
+            pos = h;
+        }
+        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
+            pos = mTrackingPosition;
+        }
+        else {
+            if (expandedPosition <= disph) {
+                pos = expandedPosition;
+            } else {
+                pos = disph;
+            }
+            pos -= disph-h;
+        }
+        mTrackingPosition = mTrackingParams.y = pos;
+        mTrackingParams.height = disph-h;
+        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+
+        if (mExpandedParams != null) {
+            mCloseView.getLocationInWindow(mPositionTmp);
+            final int closePos = mPositionTmp[1];
+
+            mExpandedContents.getLocationInWindow(mPositionTmp);
+            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
+            mExpandedParams.y = pos + mTrackingView.getHeight()
+                    - (mTrackingParams.height-closePos) - contentsBottom;
+            int max = h;
+            if (mExpandedParams.y > max) {
+                mExpandedParams.y = max;
+            }
+            int min = mTrackingPosition;
+            if (mExpandedParams.y < min) {
+                mExpandedParams.y = min;
+            }
+
+            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+            if (!visible) {
+                // if the contents aren't visible, move the expanded view way off screen
+                // because the window itself extends below the content view.
+                mExpandedParams.y = -disph;
+            }
+            visibilityChanged(visible);
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition
+                    + " mExpandedParams.y=" + mExpandedParams.y
+                    + " mExpandedParams.height=" + mExpandedParams.height);
+        }
+    }
+
+    int getExpandedHeight() {
+        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+    }
+
+    void updateExpandedHeight() {
+        if (mExpandedView != null) {
+            mExpandedParams.height = getExpandedHeight();
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+    }
+
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    private boolean mPanelSlightlyVisible;
+    void visibilityChanged(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            try {
+                mBarService.visibilityChanged(visible);
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        }
+    }
+
+    void performDisableActions(int net) {
+        int old = mDisabled;
+        int diff = net ^ old;
+        mDisabled = net;
+
+        // act accordingly
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mNotificationIcons.setVisibility(View.INVISIBLE);
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                mTicker.halt();
+            }
+        }
+    }
+
+    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            try {
+                mBarService.onClearAllNotifications();
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+            animateCollapse();
+        }
+    };
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                //collapse();
+            }
+            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                updateResources();
+            }
+        }
+    };
+
+    /**
+     * Reload some of our resources when the configuration changes.
+     * 
+     * We don't reload everything when the configuration changes -- we probably
+     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
+     * meantime, just update the things that we know change.
+     */
+    void updateResources() {
+        Resources res = getResources();
+
+        mClearButton.setText(getText(R.string.status_bar_clear_all_button));
+        mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
+        mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
+        mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        if (false) Slog.v(TAG, "updateResources");
+    }
+
+    //
+    // tracing
+    //
+
+    void postStartTracing() {
+        mHandler.postDelayed(mStartTracing, 3000);
+    }
+
+    void vibrate() {
+        android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
+        vib.vibrate(250);
+    }
+
+    Runnable mStartTracing = new Runnable() {
+        public void run() {
+            vibrate();
+            SystemClock.sleep(250);
+            Slog.d(TAG, "startTracing");
+            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
+            mHandler.postDelayed(mStopTracing, 10000);
+        }
+    };
+
+    Runnable mStopTracing = new Runnable() {
+        public void run() {
+            android.os.Debug.stopMethodTracing();
+            Slog.d(TAG, "stopTracing");
+            vibrate();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
new file mode 100644
index 0000000..5eb0d683
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.Canvas;
+import android.util.Slog;
+import android.view.ViewDebug;
+import android.widget.FrameLayout;
+
+import com.android.internal.statusbar.StatusBarIcon;
+
+public class StatusBarIconView extends AnimatedImageView {
+    private static final String TAG = "StatusBarIconView";
+
+    private StatusBarIcon mIcon;
+    @ViewDebug.ExportedProperty private String mSlot;
+    @ViewDebug.ExportedProperty private boolean mError;
+
+    public StatusBarIconView(Context context, String slot) {
+        super(context);
+        mSlot = slot;
+    }
+
+    private static boolean streq(String a, String b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null && b != null) {
+            return false;
+        }
+        if (a != null && b == null) {
+            return false;
+        }
+        return a.equals(b);
+    }
+
+    public void set(StatusBarIcon icon) {
+        error: {
+            final boolean iconEquals = !mError
+                    && mIcon != null
+                    && streq(mIcon.iconPackage, icon.iconPackage)
+                    && mIcon.iconId == icon.iconId;
+            final boolean levelEquals = !mError
+                    && iconEquals
+                    && mIcon.iconLevel == icon.iconLevel;
+            final boolean visibilityEquals = !mError
+                    && mIcon != null
+                    && mIcon.visible == icon.visible;
+            mError = false;
+            if (!iconEquals) {
+                Drawable drawable = getIcon(icon);
+                if (drawable == null) {
+                    mError = true;
+                    Slog.w(PhoneStatusBarService.TAG, "No icon ID for slot " + mSlot);
+                    break error;
+                }
+                setImageDrawable(drawable);
+            }
+            if (!levelEquals) {
+                setImageLevel(icon.iconLevel);
+            }
+            if (!visibilityEquals) {
+                setVisibility(icon.visible ? VISIBLE : GONE);
+            }
+            mIcon = icon.clone();
+        }
+        if (mError) {
+            setVisibility(GONE);
+        }
+    }
+
+    private Drawable getIcon(StatusBarIcon icon) {
+        return getIcon(getContext(), icon);
+    }
+
+    /**
+     * Returns the right icon to use for this item, respecting the iconId and
+     * iconPackage (if set)
+     * 
+     * @param context Context to use to get resources if iconPackage is not set
+     * @return Drawable for this item, or null if the package or item could not
+     *         be found
+     */
+    public static Drawable getIcon(Context context, StatusBarIcon icon) {
+        Resources r = null;
+
+        if (icon.iconPackage != null) {
+            try {
+                r = context.getPackageManager().getResourcesForApplication(icon.iconPackage);
+            } catch (PackageManager.NameNotFoundException ex) {
+                Slog.e(PhoneStatusBarService.TAG, "Icon package not found: "+icon.iconPackage, ex);
+                return null;
+            }
+        } else {
+            r = context.getResources();
+        }
+
+        if (icon.iconId == 0) {
+            return null;
+        }
+        
+        try {
+            return r.getDrawable(icon.iconId);
+        } catch (RuntimeException e) {
+            Slog.w(PhoneStatusBarService.TAG, "Icon not found in "
+                  + (icon.iconPackage != null ? icon.iconId : "<system>")
+                  + ": " + Integer.toHexString(icon.iconId));
+        }
+
+        return null;
+    }
+
+    public StatusBarIcon getStatusBarIcon() {
+        return mIcon;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
new file mode 100644
index 0000000..9ef9d0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.StatusBarManager;
+import android.app.AlertDialog;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothPbap;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.TypedArray;
+import android.graphics.PixelFormat;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.storage.StorageManager;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.text.format.DateFormat;
+import android.text.style.CharacterStyle;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.util.Slog;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.telephony.cdma.TtyIntent;
+import com.android.server.am.BatteryStatsService;
+
+import com.android.systemui.R;
+
+/**
+ * This class contains all of the policy about which icons are installed in the status
+ * bar at boot time.  It goes through the normal API for icons, even though it probably
+ * strictly doesn't need to.
+ */
+public class StatusBarPolicy {
+    private static final String TAG = "StatusBarPolicy";
+
+    // message codes for the handler
+    private static final int EVENT_BATTERY_CLOSE = 4;
+
+    private static final int AM_PM_STYLE_NORMAL  = 0;
+    private static final int AM_PM_STYLE_SMALL   = 1;
+    private static final int AM_PM_STYLE_GONE    = 2;
+
+    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+
+    private final Context mContext;
+    private final StatusBarManager mService;
+    private final Handler mHandler = new StatusBarHandler();
+    private final IBatteryStats mBatteryStats;
+
+    // storage
+    private StorageManager mStorageManager;
+
+    // battery
+    private boolean mBatteryFirst = true;
+    private boolean mBatteryPlugged;
+    private int mBatteryLevel;
+    private AlertDialog mLowBatteryDialog;
+    private TextView mBatteryLevelTextView;
+    private View mBatteryView;
+    private int mBatteryViewSequence;
+    private boolean mBatteryShowLowOnEndCall = false;
+    private static final boolean SHOW_LOW_BATTERY_WARNING = true;
+    private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
+
+    // phone
+    private TelephonyManager mPhone;
+    private int mPhoneSignalIconId;
+
+    //***** Signal strength icons
+    //GSM/UMTS
+    private static final int[] sSignalImages = new int[] {
+        R.drawable.stat_sys_signal_0,
+        R.drawable.stat_sys_signal_1,
+        R.drawable.stat_sys_signal_2,
+        R.drawable.stat_sys_signal_3,
+        R.drawable.stat_sys_signal_4
+    };
+    private static final int[] sSignalImages_r = new int[] {
+        R.drawable.stat_sys_r_signal_0,
+        R.drawable.stat_sys_r_signal_1,
+        R.drawable.stat_sys_r_signal_2,
+        R.drawable.stat_sys_r_signal_3,
+        R.drawable.stat_sys_r_signal_4
+    };
+    private static final int[] sRoamingIndicatorImages_cdma = new int[] {
+        R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
+        // 1 is Standard Roaming Indicator OFF
+        // TODO T: image never used, remove and put 0 instead?
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 2 is Standard Roaming Indicator FLASHING
+        // TODO T: image never used, remove and put 0 instead?
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 3-12 Standard ERI
+        R.drawable.stat_sys_roaming_cdma_0, //3
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 13-63 Reserved for Standard ERI
+        R.drawable.stat_sys_roaming_cdma_0, //13
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 64-127 Reserved for Non Standard (Operator Specific) ERI
+        R.drawable.stat_sys_roaming_cdma_0, //64
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0 //83
+
+        // 128-255 Reserved
+    };
+
+    //***** Data connection icons
+    private int[] mDataIconList = sDataNetType_g;
+    //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_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_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,
+        };
+    //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,
+    };
+
+    //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,
+    };
+
+    // Assume it's all good unless we hear otherwise.  We don't always seem
+    // to get broadcasts that it *is* there.
+    IccCard.State mSimState = IccCard.State.READY;
+    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+    int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    ServiceState mServiceState;
+    SignalStrength mSignalStrength;
+
+    // data connection
+    private boolean mDataIconVisible;
+    private boolean mHspaDataDistinguishable;
+
+    // ringer volume
+    private boolean mVolumeVisible;
+
+    // bluetooth device status
+    private int mBluetoothHeadsetState;
+    private boolean mBluetoothA2dpConnected;
+    private int mBluetoothPbapState;
+    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 sWifiTemporarilyNotConnectedImage =
+            R.drawable.stat_sys_wifi_signal_0;
+
+    private int mLastWifiSignalLevel = -1;
+    private boolean mIsWifiConnected = false;
+
+    // sync state
+    // If sync is active the SyncActive icon is displayed. If sync is not active but
+    // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
+
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+                updateBattery(intent);
+            }
+            else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
+                updateAlarm(intent);
+            }
+            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
+                updateSyncState(intent);
+            }
+            else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+                onBatteryLow(intent);
+            }
+            else if (action.equals(Intent.ACTION_BATTERY_OKAY)
+                    || action.equals(Intent.ACTION_POWER_CONNECTED)) {
+                onBatteryOkay(intent);
+            }
+            else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
+                    action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
+                updateBluetooth(intent);
+            }
+            else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
+                    action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
+                    action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+                updateWifi(intent);
+            }
+            else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) ||
+                    action.equals(LocationManager.GPS_FIX_CHANGE_ACTION)) {
+                updateGps(intent);
+            }
+            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
+                    action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
+                updateVolume();
+            }
+            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+                updateSimState(intent);
+            }
+            else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
+                updateTTY(intent);
+            }
+        }
+    };
+
+    public StatusBarPolicy(Context context) {
+        mContext = context;
+        mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
+        mSignalStrength = new SignalStrength();
+        mBatteryStats = BatteryStatsService.getService();
+
+        // storage
+        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+        mStorageManager.registerListener(
+                new com.android.server.status.StorageNotification(context));
+
+        // battery
+        mService.setIcon("battery", com.android.internal.R.drawable.stat_sys_battery_unknown, 0);
+
+        // phone_signal
+        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+        mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+
+        // register for phone state notifications.
+        ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
+                .listen(mPhoneStateListener,
+                          PhoneStateListener.LISTEN_SERVICE_STATE
+                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                        | PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+
+        // data_connection
+        mService.setIcon("data_connection", R.drawable.stat_sys_data_connected_g, 0);
+        mService.setIconVisibility("data_connection", false);
+
+        // wifi
+        mService.setIcon("wifi", sWifiSignalImages[0], 0);
+        mService.setIconVisibility("wifi", false);
+        // wifi will get updated by the sticky intents
+
+        // TTY status
+        mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0);
+        mService.setIconVisibility("tty", false);
+
+        // Cdma Roaming Indicator, ERI
+        mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0);
+        mService.setIconVisibility("cdma_eri", false);
+
+        // bluetooth status
+        mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0);
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            mBluetoothEnabled = adapter.isEnabled();
+        } else {
+            mBluetoothEnabled = false;
+        }
+        mBluetoothA2dpConnected = false;
+        mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
+        mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
+        mService.setIconVisibility("bluetooth", mBluetoothEnabled);
+
+        // Gps status
+        mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0);
+        mService.setIconVisibility("gps", false);
+
+        // Alarm clock
+        mService.setIcon("alarm_clock", R.drawable.stat_notify_alarm, 0);
+        mService.setIconVisibility("alarm_clock", false);
+
+        // Sync state
+        mService.setIcon("sync_active", com.android.internal.R.drawable.stat_notify_sync_anim0, 0);
+        mService.setIcon("sync_failing", com.android.internal.R.drawable.stat_notify_sync_error, 0);
+        mService.setIconVisibility("sync_active", false);
+        mService.setIconVisibility("sync_failing", false);
+
+        // volume
+        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0);
+        mService.setIconVisibility("volume", false);
+        updateVolume();
+
+        IntentFilter filter = new IntentFilter();
+
+        // Register for Intent broadcasts for...
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        filter.addAction(Intent.ACTION_BATTERY_LOW);
+        filter.addAction(Intent.ACTION_BATTERY_OKAY);
+        filter.addAction(Intent.ACTION_POWER_CONNECTED);
+        filter.addAction(Intent.ACTION_ALARM_CHANGED);
+        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
+        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
+        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
+        filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+        filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+        filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+
+        // load config to determine if to distinguish Hspa data icon
+        try {
+            mHspaDataDistinguishable = mContext.getResources().getBoolean(
+                    R.bool.config_hspa_data_distinguishable);
+        } catch (Exception e) {
+            mHspaDataDistinguishable = false;
+        }
+    }
+
+    private final void updateAlarm(Intent intent) {
+        boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
+        mService.setIconVisibility("alarm_clock", alarmSet);
+    }
+
+    private final void updateSyncState(Intent intent) {
+        boolean isActive = intent.getBooleanExtra("active", false);
+        boolean isFailing = intent.getBooleanExtra("failing", false);
+        mService.setIconVisibility("sync_active", isActive);
+        // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
+        //mService.setIconVisibility("sync_failing", isFailing && !isActive);
+    }
+
+    private final void updateBattery(Intent intent) {
+        final int id = intent.getIntExtra("icon-small", 0);
+        int level = intent.getIntExtra("level", 0);
+        mService.setIcon("battery", id, level);
+
+        boolean plugged = intent.getIntExtra("plugged", 0) != 0;
+        level = intent.getIntExtra("level", -1);
+        if (false) {
+            Slog.d(TAG, "updateBattery level=" + level
+                    + " plugged=" + plugged
+                    + " mBatteryPlugged=" + mBatteryPlugged
+                    + " mBatteryLevel=" + mBatteryLevel
+                    + " mBatteryFirst=" + mBatteryFirst);
+        }
+
+        boolean oldPlugged = mBatteryPlugged;
+
+        mBatteryPlugged = plugged;
+        mBatteryLevel = level;
+
+        if (mBatteryFirst) {
+            mBatteryFirst = false;
+        }
+        /*
+         * No longer showing the battery view because it draws attention away
+         * from the USB storage notification. We could still show it when
+         * connected to a brick, but that could lead to the user into thinking
+         * the device does not charge when plugged into USB (since he/she would
+         * not see the same battery screen on USB as he sees on brick).
+         */
+        if (false) {
+            Slog.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
+        }
+    }
+
+    private void onBatteryLow(Intent intent) {
+        if (SHOW_LOW_BATTERY_WARNING) {
+            if (false) {
+                Slog.d(TAG, "mPhoneState=" + mPhoneState
+                      + " mLowBatteryDialog=" + mLowBatteryDialog
+                      + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
+            }
+
+            if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+                showLowBatteryWarning();
+            } else {
+                mBatteryShowLowOnEndCall = true;
+            }
+        }
+    }
+
+    private void onBatteryOkay(Intent intent) {
+        if (mLowBatteryDialog != null
+                && SHOW_LOW_BATTERY_WARNING) {
+            mLowBatteryDialog.dismiss();
+            mBatteryShowLowOnEndCall = false;
+        }
+    }
+
+    private void setBatteryLevel(View parent, int id, int height, int background, int level) {
+        ImageView v = (ImageView)parent.findViewById(id);
+        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
+        lp.weight = height;
+        if (background != 0) {
+            v.setBackgroundResource(background);
+            Drawable bkg = v.getBackground();
+            bkg.setLevel(level);
+        }
+    }
+
+    private void showLowBatteryWarning() {
+        closeLastBatteryView();
+
+        // Show exact battery level.
+        CharSequence levelText = mContext.getString(
+                    R.string.battery_low_percent_format, mBatteryLevel);
+
+        if (mBatteryLevelTextView != null) {
+            mBatteryLevelTextView.setText(levelText);
+        } else {
+            View v = View.inflate(mContext, R.layout.battery_low, null);
+            mBatteryLevelTextView=(TextView)v.findViewById(R.id.level_percent);
+
+            mBatteryLevelTextView.setText(levelText);
+
+            AlertDialog.Builder b = new AlertDialog.Builder(mContext);
+                b.setCancelable(true);
+                b.setTitle(R.string.battery_low_title);
+                b.setView(v);
+                b.setIcon(android.R.drawable.ic_dialog_alert);
+                b.setPositiveButton(android.R.string.ok, null);
+
+                final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                        | Intent.FLAG_ACTIVITY_NO_HISTORY);
+                if (intent.resolveActivity(mContext.getPackageManager()) != null) {
+                    b.setNegativeButton(R.string.battery_low_why,
+                            new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            mContext.startActivity(intent);
+                            if (mLowBatteryDialog != null) {
+                                mLowBatteryDialog.dismiss();
+                            }
+                        }
+                    });
+                }
+
+            AlertDialog d = b.create();
+            d.setOnDismissListener(mLowBatteryListener);
+            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            d.show();
+            mLowBatteryDialog = d;
+        }
+
+        final ContentResolver cr = mContext.getContentResolver();
+        if (Settings.System.getInt(cr,
+                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
+        {
+            final String soundPath = Settings.System.getString(cr,
+                Settings.System.LOW_BATTERY_SOUND);
+            if (soundPath != null) {
+                final Uri soundUri = Uri.parse("file://" + soundPath);
+                if (soundUri != null) {
+                    final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                    if (sfx != null) {
+                        sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                        sfx.play();
+                    }
+                }
+            }
+        }
+    }
+
+    private final void updateCallState(int state) {
+        mPhoneState = state;
+        if (false) {
+            Slog.d(TAG, "mPhoneState=" + mPhoneState
+                    + " mLowBatteryDialog=" + mLowBatteryDialog
+                    + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
+        }
+        if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+            if (mBatteryShowLowOnEndCall) {
+                if (!mBatteryPlugged) {
+                    showLowBatteryWarning();
+                }
+                mBatteryShowLowOnEndCall = false;
+            }
+        } else {
+            if (mLowBatteryDialog != null) {
+                mLowBatteryDialog.dismiss();
+                mBatteryShowLowOnEndCall = true;
+            }
+        }
+    }
+
+    private DialogInterface.OnDismissListener mLowBatteryListener
+            = new DialogInterface.OnDismissListener() {
+        public void onDismiss(DialogInterface dialog) {
+            mLowBatteryDialog = null;
+            mBatteryLevelTextView = null;
+        }
+    };
+
+    private void scheduleCloseBatteryView() {
+        Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
+        m.arg1 = (++mBatteryViewSequence);
+        mHandler.sendMessageDelayed(m, 3000);
+    }
+
+    private void closeLastBatteryView() {
+        if (mBatteryView != null) {
+            //mBatteryView.debug();
+            WindowManagerImpl.getDefault().removeView(mBatteryView);
+            mBatteryView = null;
+        }
+    }
+
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            mSignalStrength = signalStrength;
+            updateSignalStrength();
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            mServiceState = state;
+            updateSignalStrength();
+            updateCdmaRoamingIcon(state);
+            updateDataIcon();
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            updateCallState(state);
+            // In cdma, if a voice call is made, RSSI should switch to 1x.
+            if (isCdma()) {
+                updateSignalStrength();
+            }
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            mDataState = state;
+            updateDataNetType(networkType);
+            updateDataIcon();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            mDataActivity = direction;
+            updateDataIcon();
+        }
+    };
+
+    private final void updateSimState(Intent intent) {
+        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
+        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+            mSimState = IccCard.State.ABSENT;
+        }
+        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+            mSimState = IccCard.State.READY;
+        }
+        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
+            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                mSimState = IccCard.State.PIN_REQUIRED;
+            }
+            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                mSimState = IccCard.State.PUK_REQUIRED;
+            }
+            else {
+                mSimState = IccCard.State.NETWORK_LOCKED;
+            }
+        } else {
+            mSimState = IccCard.State.UNKNOWN;
+        }
+        updateDataIcon();
+    }
+
+    private boolean isCdma() {
+        return (mSignalStrength != null) && !mSignalStrength.isGsm();
+    }
+
+    private boolean isEvdo() {
+        return ( (mServiceState != null)
+                 && ((mServiceState.getRadioTechnology()
+                        == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
+                     || (mServiceState.getRadioTechnology()
+                        == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
+                     || (mServiceState.getRadioTechnology()
+                        == ServiceState.RADIO_TECHNOLOGY_EVDO_B)));
+    }
+
+    private boolean hasService() {
+        if (mServiceState != null) {
+            switch (mServiceState.getState()) {
+                case ServiceState.STATE_OUT_OF_SERVICE:
+                case ServiceState.STATE_POWER_OFF:
+                    return false;
+                default:
+                    return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private final void updateSignalStrength() {
+        int iconLevel = -1;
+        int[] iconList;
+
+        // Display signal strength while in "emergency calls only" mode
+        if (!hasService() && !mServiceState.isEmergencyOnly()) {
+            //Slog.d(TAG, "updateSignalStrength: no service");
+            if (Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_flightmode;
+            } else {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+            }
+            mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+            return;
+        }
+
+        if (!isCdma()) {
+            int asu = mSignalStrength.getGsmSignalStrength();
+
+            // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+            // asu = 0 (-113dB or less) is very weak
+            // signal, its better to show 0 bars to the user in such cases.
+            // asu = 99 is a special case, where the signal strength is unknown.
+            if (asu <= 2 || asu == 99) iconLevel = 0;
+            else if (asu >= 12) iconLevel = 4;
+            else if (asu >= 8)  iconLevel = 3;
+            else if (asu >= 5)  iconLevel = 2;
+            else iconLevel = 1;
+
+            // Though mPhone is a Manager, this call is not an IPC
+            if (mPhone.isNetworkRoaming()) {
+                iconList = sSignalImages_r;
+            } else {
+                iconList = sSignalImages;
+            }
+        } else {
+            iconList = this.sSignalImages;
+
+            // If 3G(EV) and 1x network are available than 3G should be
+            // displayed, displayed RSSI should be from the EV side.
+            // If a voice call is made then RSSI should switch to 1x.
+            if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
+                iconLevel = getEvdoLevel();
+                if (false) {
+                    Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+                }
+            } else {
+                iconLevel = getCdmaLevel();
+            }
+        }
+        mPhoneSignalIconId = iconList[iconLevel];
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+    }
+
+    private int getCdmaLevel() {
+        final int cdmaDbm = mSignalStrength.getCdmaDbm();
+        final int cdmaEcio = mSignalStrength.getCdmaEcio();
+        int levelDbm = 0;
+        int levelEcio = 0;
+
+        if (cdmaDbm >= -75) levelDbm = 4;
+        else if (cdmaDbm >= -85) levelDbm = 3;
+        else if (cdmaDbm >= -95) levelDbm = 2;
+        else if (cdmaDbm >= -100) levelDbm = 1;
+        else levelDbm = 0;
+
+        // Ec/Io are in dB*10
+        if (cdmaEcio >= -90) levelEcio = 4;
+        else if (cdmaEcio >= -110) levelEcio = 3;
+        else if (cdmaEcio >= -130) levelEcio = 2;
+        else if (cdmaEcio >= -150) levelEcio = 1;
+        else levelEcio = 0;
+
+        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
+    }
+
+    private int getEvdoLevel() {
+        int evdoDbm = mSignalStrength.getEvdoDbm();
+        int evdoSnr = mSignalStrength.getEvdoSnr();
+        int levelEvdoDbm = 0;
+        int levelEvdoSnr = 0;
+
+        if (evdoDbm >= -65) levelEvdoDbm = 4;
+        else if (evdoDbm >= -75) levelEvdoDbm = 3;
+        else if (evdoDbm >= -90) levelEvdoDbm = 2;
+        else if (evdoDbm >= -105) levelEvdoDbm = 1;
+        else levelEvdoDbm = 0;
+
+        if (evdoSnr >= 7) levelEvdoSnr = 4;
+        else if (evdoSnr >= 5) levelEvdoSnr = 3;
+        else if (evdoSnr >= 3) levelEvdoSnr = 2;
+        else if (evdoSnr >= 1) levelEvdoSnr = 1;
+        else levelEvdoSnr = 0;
+
+        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
+    }
+
+    private final void updateDataNetType(int net) {
+        switch (net) {
+        case TelephonyManager.NETWORK_TYPE_EDGE:
+            mDataIconList = sDataNetType_e;
+            break;
+        case TelephonyManager.NETWORK_TYPE_UMTS:
+            mDataIconList = sDataNetType_3g;
+            break;
+        case TelephonyManager.NETWORK_TYPE_HSDPA:
+        case TelephonyManager.NETWORK_TYPE_HSUPA:
+        case TelephonyManager.NETWORK_TYPE_HSPA:
+            if (mHspaDataDistinguishable) {
+                mDataIconList = sDataNetType_h;
+            } else {
+                mDataIconList = sDataNetType_3g;
+            }
+            break;
+        case TelephonyManager.NETWORK_TYPE_CDMA:
+            // display 1xRTT for IS95A/B
+            mDataIconList = this.sDataNetType_1x;
+            break;
+        case TelephonyManager.NETWORK_TYPE_1xRTT:
+            mDataIconList = this.sDataNetType_1x;
+            break;
+        case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+        case TelephonyManager.NETWORK_TYPE_EVDO_A:
+        case TelephonyManager.NETWORK_TYPE_EVDO_B:
+            mDataIconList = sDataNetType_3g;
+            break;
+        default:
+            mDataIconList = sDataNetType_g;
+        break;
+        }
+    }
+
+    private final void updateDataIcon() {
+        int iconId;
+        boolean visible = true;
+
+        if (!isCdma()) {
+            // GSM case, we have to check also the sim state
+            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
+                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                    switch (mDataActivity) {
+                        case TelephonyManager.DATA_ACTIVITY_IN:
+                            iconId = mDataIconList[1];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_OUT:
+                            iconId = mDataIconList[2];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_INOUT:
+                            iconId = mDataIconList[3];
+                            break;
+                        default:
+                            iconId = mDataIconList[0];
+                            break;
+                    }
+                    mService.setIcon("data_connection", iconId, 0);
+                } else {
+                    visible = false;
+                }
+            } else {
+                iconId = R.drawable.stat_sys_no_sim;
+                mService.setIcon("data_connection", iconId, 0);
+            }
+        } else {
+            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                switch (mDataActivity) {
+                    case TelephonyManager.DATA_ACTIVITY_IN:
+                        iconId = mDataIconList[1];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_OUT:
+                        iconId = mDataIconList[2];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_INOUT:
+                        iconId = mDataIconList[3];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
+                    default:
+                        iconId = mDataIconList[0];
+                        break;
+                }
+                mService.setIcon("data_connection", iconId, 0);
+            } else {
+                visible = false;
+            }
+        }
+
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        if (mDataIconVisible != visible) {
+            mService.setIconVisibility("data_connection", visible);
+            mDataIconVisible = visible;
+        }
+    }
+
+    private final void updateVolume() {
+        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        final int ringerMode = audioManager.getRingerMode();
+        final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
+                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+        final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
+                ? R.drawable.stat_sys_ringer_vibrate
+                : R.drawable.stat_sys_ringer_silent;
+
+        if (visible) {
+            mService.setIcon("volume", iconId, 0);
+        }
+        if (visible != mVolumeVisible) {
+            mService.setIconVisibility("volume", visible);
+            mVolumeVisible = visible;
+        }
+    }
+
+    private final void updateBluetooth(Intent intent) {
+        int iconId = R.drawable.stat_sys_data_bluetooth;
+        String action = intent.getAction();
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+            mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
+        } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
+            mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+                    BluetoothHeadset.STATE_ERROR);
+        } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
+            BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+            if (a2dp.getConnectedSinks().size() != 0) {
+                mBluetoothA2dpConnected = true;
+            } else {
+                mBluetoothA2dpConnected = false;
+            }
+        } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
+            mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
+                    BluetoothPbap.STATE_DISCONNECTED);
+        } else {
+            return;
+        }
+
+        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
+                mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
+            iconId = R.drawable.stat_sys_data_bluetooth_connected;
+        }
+
+        mService.setIcon("bluetooth", iconId, 0);
+        mService.setIconVisibility("bluetooth", mBluetoothEnabled);
+    }
+
+    private final void updateWifi(Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+
+            final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+
+            if (!enabled) {
+                // If disabled, hide the icon. (We show icon when connected.)
+                mService.setIconVisibility("wifi", false);
+            }
+
+        } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
+            final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
+                                                           false);
+            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];
+                }
+
+                // Show the icon since wi-fi is connected
+                mService.setIconVisibility("wifi", true);
+
+            } else {
+                mLastWifiSignalLevel = -1;
+                mIsWifiConnected = false;
+                iconId = sWifiSignalImages[0];
+
+                // Hide the icon since we're not connected
+                mService.setIconVisibility("wifi", false);
+            }
+
+            mService.setIcon("wifi", iconId, 0);
+        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+            int iconId;
+            final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
+                                                                  sWifiSignalImages.length);
+            if (newSignalLevel != mLastWifiSignalLevel) {
+                mLastWifiSignalLevel = newSignalLevel;
+                if (mIsWifiConnected) {
+                    iconId = sWifiSignalImages[newSignalLevel];
+                } else {
+                    iconId = sWifiTemporarilyNotConnectedImage;
+                }
+                mService.setIcon("wifi", iconId, 0);
+            }
+        }
+    }
+
+    private final void updateGps(Intent intent) {
+        final String action = intent.getAction();
+        final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
+
+        if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
+            // GPS is getting fixes
+            mService.setIcon("gps", com.android.internal.R.drawable.stat_sys_gps_on, 0);
+            mService.setIconVisibility("gps", true);
+        } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
+            // GPS is off
+            mService.setIconVisibility("gps", false);
+        } else {
+            // GPS is on, but not receiving fixes
+            mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0);
+            mService.setIconVisibility("gps", true);
+        }
+    }
+
+    private final void updateTTY(Intent intent) {
+        final String action = intent.getAction();
+        final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
+
+        if (false) Slog.v(TAG, "updateTTY: enabled: " + enabled);
+
+        if (enabled) {
+            // TTY is on
+            if (false) Slog.v(TAG, "updateTTY: set TTY on");
+            mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0);
+            mService.setIconVisibility("tty", true);
+        } else {
+            // TTY is off
+            if (false) Slog.v(TAG, "updateTTY: set TTY off");
+            mService.setIconVisibility("tty", false);
+        }
+    }
+
+    private final void updateCdmaRoamingIcon(ServiceState state) {
+        if (!hasService()) {
+            mService.setIconVisibility("cdma_eri", false);
+            return;
+        }
+
+        if (!isCdma()) {
+            mService.setIconVisibility("cdma_eri", false);
+            return;
+        }
+
+        int[] iconList = sRoamingIndicatorImages_cdma;
+        int iconIndex = state.getCdmaEriIconIndex();
+        int iconMode = state.getCdmaEriIconMode();
+
+        if (iconIndex == -1) {
+            Slog.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
+            return;
+        }
+
+        if (iconMode == -1) {
+            Slog.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
+            return;
+        }
+
+        if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
+            if (false) Slog.v(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
+            mService.setIconVisibility("cdma_eri", false);
+            return;
+        }
+
+        switch (iconMode) {
+            case EriInfo.ROAMING_ICON_MODE_NORMAL:
+                mService.setIcon("cdma_eri", iconList[iconIndex], 0);
+                mService.setIconVisibility("cdma_eri", true);
+                break;
+            case EriInfo.ROAMING_ICON_MODE_FLASH:
+                mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_flash, 0);
+                mService.setIconVisibility("cdma_eri", true);
+                break;
+
+        }
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+    }
+
+
+    private class StatusBarHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case EVENT_BATTERY_CLOSE:
+                if (msg.arg1 == mBatteryViewSequence) {
+                    closeLastBatteryView();
+                }
+                break;
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
new file mode 100644
index 0000000..4d9e695
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+
+public abstract class StatusBarService extends Service implements CommandQueue.Callbacks {
+    private static final String TAG = "StatusBarService";
+
+    CommandQueue mCommandQueue;
+    IStatusBarService mBarService;
+
+    /* TODO
+    H mHandler = new H();
+    Object mQueueLock = new Object();
+    NotificationCallbacks mNotificationCallbacks;
+    */
+
+    @Override
+    public void onCreate() {
+        // Connect in to the status bar manager service
+        StatusBarIconList iconList = new StatusBarIconList();
+        ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
+        ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
+        mCommandQueue = new CommandQueue(this, iconList);
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        try {
+            mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications);
+        } catch (RemoteException ex) {
+            // If the system process isn't there we're doomed anyway.
+        }
+
+        // Set up the initial icon state
+        int N = iconList.size();
+        int viewIndex = 0;
+        for (int i=0; i<N; i++) {
+            StatusBarIcon icon = iconList.getIcon(i);
+            if (icon != null) {
+                addIcon(iconList.getSlot(i), i, viewIndex, icon);
+                viewIndex++;
+            }
+        }
+
+        // Set up the initial notification state
+        N = notificationKeys.size();
+        if (N == notifications.size()) {
+            for (int i=0; i<N; i++) {
+                addNotification(notificationKeys.get(i), notifications.get(i));
+            }
+        } else {
+            Log.wtf(TAG, "Notification list length mismatch: keys=" + N
+                    + " notifications=" + notifications.size());
+        }
+
+        // Put up the view
+        addStatusBarView();
+    }
+
+    @Override
+    public void onDestroy() {
+        // we're never destroyed
+    }
+
+    /**
+     * Nobody binds to us.
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    /**
+     * Implement this to add the main status bar view.
+     */
+    protected abstract void addStatusBarView();
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStarter.java
new file mode 100644
index 0000000..2b9dfb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStarter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.util.Log;
+
+/**
+ * Receive a broadcast from the StatusBarManagerService at boot time, and
+ * kick off the StatusBarService.
+ */
+public class StatusBarStarter extends BroadcastReceiver {
+    private static final String TAG = "StatusBarStarter";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "StatusBarStarter onReceive intent=" + intent);
+        context.startService(new Intent(context, PhoneStatusBarService.class));
+    }
+}
+
+
diff --git a/services/java/com/android/server/status/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
similarity index 96%
rename from services/java/com/android/server/status/StatusBarView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
index 5e1f572..466cc75 100644
--- a/services/java/com/android/server/status/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -27,14 +27,14 @@
 import android.view.ViewParent;
 import android.widget.FrameLayout;
 
-import com.android.internal.R;
+import com.android.systemui.R;
 
 public class StatusBarView extends FrameLayout {
     private static final String TAG = "StatusBarView";
 
     static final int DIM_ANIM_TIME = 400;
     
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
     ViewGroup mNotificationIcons;
@@ -94,7 +94,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+        mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
     }
 
     @Override
diff --git a/services/java/com/android/server/status/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
similarity index 79%
rename from services/java/com/android/server/status/Ticker.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
index e47185b..07e8653 100644
--- a/services/java/com/android/server/status/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
-
-import com.android.internal.R;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -35,12 +33,24 @@
 
 import java.util.ArrayList;
 
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarNotification;
+import com.android.internal.util.CharSequences;
+import com.android.systemui.R;
 
-abstract class Ticker {
+public abstract class Ticker {
     private static final int TICKER_SEGMENT_DELAY = 3000;
     
+    private Context mContext;
+    private Handler mHandler = new Handler();
+    private ArrayList<Segment> mSegments = new ArrayList();
+    private TextPaint mPaint;
+    private View mTickerView;
+    private ImageSwitcher mIconSwitcher;
+    private TextSwitcher mTextSwitcher;
+
     private final class Segment {
-        NotificationData notificationData;
+        StatusBarNotification notification;
         Drawable icon;
         CharSequence text;
         int current;
@@ -116,8 +126,8 @@
             return null;
         }
 
-        Segment(NotificationData n, Drawable icon, CharSequence text) {
-            this.notificationData = n;
+        Segment(StatusBarNotification n, Drawable icon, CharSequence text) {
+            this.notification = n;
             this.icon = icon;
             this.text = text;
             int index = 0;
@@ -131,14 +141,8 @@
         }
     };
 
-    private Handler mHandler = new Handler();
-    private ArrayList<Segment> mSegments = new ArrayList();
-    private TextPaint mPaint;
-    private View mTickerView;
-    private ImageSwitcher mIconSwitcher;
-    private TextSwitcher mTextSwitcher;
-
     Ticker(Context context, StatusBarView sb) {
+        mContext = context;
         mTickerView = sb.findViewById(R.id.ticker);
 
         mIconSwitcher = (ImageSwitcher)sb.findViewById(R.id.tickerIcon);
@@ -158,20 +162,34 @@
         mPaint = text.getPaint();
     }
 
-    void addEntry(NotificationData n, Drawable icon, CharSequence text) {
+
+    void addEntry(StatusBarNotification n) {
         int initialCount = mSegments.size();
 
-        Segment newSegment = new Segment(n, icon, text);
+        // If what's being displayed has the same text and icon, just drop it
+        // (which will let the current one finish, this happens when apps do
+        // a notification storm).
+        if (initialCount > 0) {
+            final Segment seg = mSegments.get(0);
+            if (n.pkg.equals(seg.notification.pkg)
+                    && n.notification.icon == seg.notification.notification.icon
+                    && n.notification.iconLevel == seg.notification.notification.iconLevel
+                    && CharSequences.equals(seg.notification.notification.tickerText,
+                        n.notification.tickerText)) {
+                return;
+            }
+        }
 
-        // prune out any preexisting ones for this notification, but not the current one.
-        // let that finish, even if it's the same id
-        for (int i=1; i<initialCount; i++) {
+        final Drawable icon = StatusBarIconView.getIcon(mContext,
+                new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0));
+        final Segment newSegment = new Segment(n, icon, n.notification.tickerText);
+
+        // If there's already a notification schedule for this package and id, remove it.
+        for (int i=0; i<initialCount; i++) {
             Segment seg = mSegments.get(i);
-            if (n.id == seg.notificationData.id && n.pkg.equals(seg.notificationData.pkg)) {
+            if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
                 // just update that one to use this new data instead
-                mSegments.set(i, newSegment);
-                // and since we know initialCount != 0, just return
-                return ;
+                mSegments.remove(i);
             }
         }
 
@@ -194,6 +212,15 @@
         }
     }
 
+    void removeEntry(StatusBarNotification n) {
+        for (int i=mSegments.size()-1; i>=0; i--) {
+            Segment seg = mSegments.get(i);
+            if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
+                mSegments.remove(i);
+            }
+        }
+    }
+
     void halt() {
         mHandler.removeCallbacks(mAdvanceTicker);
         mSegments.clear();
diff --git a/services/java/com/android/server/status/TickerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
similarity index 95%
rename from services/java/com/android/server/status/TickerView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
index 099dffb..9749ae4 100644
--- a/services/java/com/android/server/status/TickerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/services/java/com/android/server/status/TrackingPatternView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
similarity index 97%
rename from services/java/com/android/server/status/TrackingPatternView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
index 2c91aa4..ba6f15d 100644
--- a/services/java/com/android/server/status/TrackingPatternView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/services/java/com/android/server/status/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
similarity index 93%
rename from services/java/com/android/server/status/TrackingView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
index 8ec39c0..c59eb6a 100644
--- a/services/java/com/android/server/status/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -26,7 +26,7 @@
 
 public class TrackingView extends LinearLayout {
     final Display mDisplay;
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
 
@@ -48,7 +48,7 @@
         switch (event.getKeyCode()) {
         case KeyEvent.KEYCODE_BACK:
             if (down) {
-                mService.deactivate();
+                //mService.deactivate();
             }
             return true;
         }
diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java
index c255041..eb61f5e 100644
--- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -145,8 +145,8 @@
     private Context mContext;
     private AlarmManager mAlarmManager;
     private StatusBarManager mStatusBarManager;
-    private boolean mShowLockIcon = false;
-    private IBinder mSecureLockIcon = null;
+    private boolean mShowLockIcon;
+    private boolean mShowingLockIcon;
 
     private boolean mSystemReady;
 
@@ -1036,14 +1036,15 @@
             if (mShowLockIcon) {
                 // Give feedback to user when secure keyguard is active and engaged
                 if (mShowing && isSecure()) {
-                    if (mSecureLockIcon == null) {
-                        mSecureLockIcon = mStatusBarManager.addIcon("secure",
-                            com.android.internal.R.drawable.stat_sys_secure, 0);
+                    if (!mShowingLockIcon) {
+                        mStatusBarManager.setIcon("secure",
+                                com.android.internal.R.drawable.stat_sys_secure, 0);
+                        mShowingLockIcon = true;
                     }
                 } else {
-                    if (mSecureLockIcon != null) {
-                        mStatusBarManager.removeIcon(mSecureLockIcon);
-                        mSecureLockIcon = null;
+                    if (mShowingLockIcon) {
+                        mStatusBarManager.removeIcon("secure");
+                        mShowingLockIcon = false;
                     }
                 }
             }
diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 8fdff92..60cd56c 100644
--- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -53,6 +53,8 @@
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final KeyguardScreenCallback mCallback;
 
+    private boolean mIsAlpha;
+
     private EditText mPasswordEntry;
     private Button mEmergencyCallButton;
     private LockPatternUtils mLockPatternUtils;
@@ -87,7 +89,7 @@
         }
 
         final int quality = lockPatternUtils.getKeyguardStoredPasswordQuality();
-        final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
+        mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
                 || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality
                 || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality;
 
@@ -100,7 +102,7 @@
         mTitle = (TextView) findViewById(R.id.enter_password_label);
 
         mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this);
-        mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
+        mKeyboardHelper.setKeyboardMode(mIsAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
                 : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
 
         mKeyboardView.setVisibility(mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
@@ -109,7 +111,7 @@
 
         // This allows keyboards with overlapping qwerty/numeric keys to choose just the
         // numeric keys.
-        if (isAlpha) {
+        if (mIsAlpha) {
             mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
         } else {
             mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
@@ -140,6 +142,7 @@
     public void onResume() {
         // start fresh
         mPasswordEntry.setText("");
+        resetStatusInfo();
         mPasswordEntry.requestFocus();
         mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
 
@@ -176,6 +179,9 @@
                 long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
                 handleAttemptLockout(deadline);
             }
+            mTitle.setText(R.string.lockscreen_password_wrong);
+        } else if (entry.length() > 0) {
+            mTitle.setText(R.string.lockscreen_password_wrong);
         }
         mPasswordEntry.setText("");
     }
@@ -199,16 +205,8 @@
             @Override
             public void onFinish() {
                 mPasswordEntry.setEnabled(true);
-                final int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
-                final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
-                        || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality
-                        || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality;
-                if(isAlpha) {
-                    mTitle.setText(R.string.keyguard_password_enter_password_code);
-                } else {
-                    mTitle.setText(R.string.keyguard_password_enter_pin_password_code);
-                }
                 mKeyboardView.setEnabled(true);
+                resetStatusInfo();
             }
         }.start();
     }
@@ -274,4 +272,12 @@
 
     }
 
+    private void resetStatusInfo() {
+        if(mIsAlpha) {
+            mTitle.setText(R.string.keyguard_password_enter_password_code);
+        } else {
+            mTitle.setText(R.string.keyguard_password_enter_pin_password_code);
+        }
+    }
+
 }
diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
index a7c278b..73a57ee 100755
--- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
-import android.app.IStatusBar;
 import android.app.IUiModeManager;
 import android.app.UiModeManager;
 import android.content.ActivityNotFoundException;
@@ -47,6 +46,7 @@
 import android.provider.Settings;
 
 import com.android.internal.policy.PolicyManager;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.widget.PointerLocationView;
 
@@ -1140,22 +1140,6 @@
                     return true;
                 }
             }
-        } else if (code == KeyEvent.KEYCODE_NOTIFICATION) {
-            if (down) {
-                // this key doesn't exist on current hardware, but if a device
-                // didn't have a touchscreen, it would want one of these to open
-                // the status bar.
-                IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
-                if (sbs != null) {
-                    try {
-                        sbs.toggle();
-                    } catch (RemoteException e) {
-                        // we're screwed anyway, since it's in this process
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-            return true;
         } else if (code == KeyEvent.KEYCODE_SEARCH) {
             if (down) {
                 if (repeatCount == 0) {
@@ -1537,11 +1521,11 @@
         }
         
         if (changes != 0 && hiding) {
-            IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
+            IStatusBarService sbs = IStatusBarService.Stub.asInterface(ServiceManager.getService("statusbar"));
             if (sbs != null) {
                 try {
                     // Make sure the window shade is hidden.
-                    sbs.deactivate();
+                    sbs.collapse();
                 } catch (RemoteException e) {
                 }
             }
diff --git a/preloaded-classes b/preloaded-classes
index 931ea1e..4098cbf 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -31,7 +31,6 @@
 android.app.IActivityManager
 android.app.IActivityManager$ContentProviderHolder
 android.app.IAlarmManager$Stub
-android.app.IStatusBar$Stub
 android.app.ITransientNotification$Stub
 android.app.Instrumentation
 android.app.IntentService
@@ -654,6 +653,11 @@
 com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState
 com.android.internal.policy.impl.PhoneWindowManager
 com.android.internal.policy.impl.Policy
+com.android.internal.statusbar.IStatusBar
+com.android.internal.statusbar.IStatusBar$Stub
+com.android.internal.statusbar.IStatusBarService$Stub
+com.android.internal.statusbar.IStatusBarService$Stub
+com.android.internal.statusbar.StatusBarIcon
 com.android.internal.telephony.GsmAlphabet
 com.android.internal.telephony.ITelephony$Stub
 com.android.internal.telephony.ITelephony$Stub$Proxy
@@ -725,7 +729,6 @@
 java.io.File
 java.io.FileDescriptor
 java.io.FileInputStream
-java.io.FileInputStream$RepositioningLock
 java.io.FileNotFoundException
 java.io.FileOutputStream
 java.io.FilterInputStream
@@ -1116,7 +1119,6 @@
 org.apache.harmony.luni.util.InputStreamHelper$1
 org.apache.harmony.luni.util.InputStreamHelper$ExposedByteArrayInputStream
 org.apache.harmony.luni.util.LocaleCache
-org.apache.harmony.luni.util.Msg
 org.apache.harmony.luni.util.NumberConverter
 org.apache.harmony.luni.util.PriviAction
 org.apache.harmony.luni.util.ThreadLocalCache
@@ -1129,7 +1131,6 @@
 org.apache.harmony.nio.FileChannelFactory
 org.apache.harmony.nio.internal.DirectBuffer
 org.apache.harmony.nio.internal.FileChannelImpl
-org.apache.harmony.nio.internal.FileChannelImpl$RepositioningLock
 org.apache.harmony.nio.internal.FileLockImpl
 org.apache.harmony.nio.internal.LockManager
 org.apache.harmony.nio.internal.LockManager$1
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 90c456c..4b86135 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -26,8 +26,7 @@
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.InputBindResult;
 
-import com.android.server.status.IconData;
-import com.android.server.status.StatusBarService;
+import com.android.server.status.StatusBarManagerService;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -110,9 +109,7 @@
     final Context mContext;
     final Handler mHandler;
     final SettingsObserver mSettingsObserver;
-    final StatusBarService mStatusBar;
-    final IBinder mInputMethodIcon;
-    final IconData mInputMethodData;
+    final StatusBarManagerService mStatusBar;
     final IWindowManager mIWindowManager;
     final HandlerCaller mCaller;
 
@@ -447,7 +444,7 @@
         }
     }
 
-    public InputMethodManagerService(Context context, StatusBarService statusBar) {
+    public InputMethodManagerService(Context context, StatusBarManagerService statusBar) {
         mContext = context;
         mHandler = new Handler(this);
         mIWindowManager = IWindowManager.Stub.asInterface(
@@ -510,9 +507,7 @@
         }
 
         mStatusBar = statusBar;
-        mInputMethodData = IconData.makeIcon("ime", null, 0, 0, 0);
-        mInputMethodIcon = statusBar.addIcon(mInputMethodData, null);
-        statusBar.setIconVisibility(mInputMethodIcon, false);
+        statusBar.setIconVisibility("ime", false);
 
         mSettingsObserver = new SettingsObserver(mHandler);
         updateFromSettingsLocked();
@@ -914,7 +909,7 @@
             mEnabledSession = null;
             mCurMethod = null;
         }
-        mStatusBar.setIconVisibility(mInputMethodIcon, false);
+        mStatusBar.setIconVisibility("ime", false);
     }
 
     public void onServiceDisconnected(ComponentName name) {
@@ -948,13 +943,11 @@
             synchronized (mMethodMap) {
                 if (iconId == 0) {
                     if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
-                    mStatusBar.setIconVisibility(mInputMethodIcon, false);
+                    mStatusBar.setIconVisibility("ime", false);
                 } else if (packageName != null) {
                     if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
-                    mInputMethodData.iconId = iconId;
-                    mInputMethodData.iconPackage = packageName;
-                    mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
-                    mStatusBar.setIconVisibility(mInputMethodIcon, true);
+                    mStatusBar.setIcon("ime", packageName, iconId, 0);
+                    mStatusBar.setIconVisibility("ime", true);
                 }
             }
         } finally {
@@ -1736,8 +1729,6 @@
                 p.println("    sessionRequested=" + ci.sessionRequested);
                 p.println("    curSession=" + ci.curSession);
             }
-            p.println("  mInputMethodIcon=" + mInputMethodIcon);
-            p.println("  mInputMethodData=" + mInputMethodData);
             p.println("  mCurMethodId=" + mCurMethodId);
             client = mCurClient;
             p.println("  mCurClient=" + client + " mCurSeq=" + mCurSeq);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6ceeb95..6c2f1b2 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -642,10 +642,21 @@
     }
 
     private boolean doGetShareMethodAvailable(String method) {
-        ArrayList<String> rsp = mConnector.doCommand("share status " + method);
+        ArrayList<String> rsp;
+        try {
+            rsp = mConnector.doCommand("share status " + method);
+        } catch (NativeDaemonConnectorException ex) {
+            Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
+            return false;
+        }
 
         for (String line : rsp) {
-            String []tok = line.split(" ");
+            String[] tok = line.split(" ");
+            if (tok.length < 3) {
+                Slog.e(TAG, "Malformed response to share status " + method);
+                return false;
+            }
+
             int code;
             try {
                 code = Integer.parseInt(tok[0]);
@@ -770,10 +781,22 @@
 
     private boolean doGetVolumeShared(String path, String method) {
         String cmd = String.format("volume shared %s %s", path, method);
-        ArrayList<String> rsp = mConnector.doCommand(cmd);
+        ArrayList<String> rsp;
+
+        try {
+            rsp = mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException ex) {
+            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
+            return false;
+        }
 
         for (String line : rsp) {
-            String []tok = line.split(" ");
+            String[] tok = line.split(" ");
+            if (tok.length < 3) {
+                Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command");
+                return false;
+            }
+
             int code;
             try {
                 code = Integer.parseInt(tok[0]);
@@ -782,9 +805,7 @@
                 return false;
             }
             if (code == VoldResponseCode.ShareEnabledResult) {
-                if (tok[2].equals("enabled"))
-                    return true;
-                return false;
+                return "enabled".equals(tok[2]);
             } else {
                 Slog.e(TAG, String.format("Unexpected response code %d", code));
                 return false;
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 08d7ce6..c452590 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -128,12 +128,11 @@
                                     Slog.e(TAG, String.format(
                                             "Error handling '%s'", event), ex);
                                 }
-                            } else {
-                                try {
-                                    mResponseQueue.put(event);
-                                } catch (InterruptedException ex) {
-                                    Slog.e(TAG, "Failed to put response onto queue", ex);
-                                }
+                            }
+                            try {
+                                mResponseQueue.put(event);
+                            } catch (InterruptedException ex) {
+                                Slog.e(TAG, "Failed to put response onto queue", ex);
                             }
                         } catch (NumberFormatException nfe) {
                             Slog.w(TAG, String.format("Bad msg (%s)", event));
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index cbbc7be..c156150 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -35,6 +35,7 @@
 import android.util.Log;
 import android.util.Slog;
 import java.util.ArrayList;
+import java.util.NoSuchElementException;
 import java.util.StringTokenizer;
 import android.provider.Settings;
 import android.content.ContentResolver;
@@ -226,44 +227,61 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
-        return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
+        try {
+            return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Cannot communicate with native daemon to list interfaces");
+        }
     }
 
     public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
-        String rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
+        String rsp;
+        try {
+            rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Cannot communicate with native daemon to get interface config");
+        }
         Slog.d(TAG, String.format("rsp <%s>", rsp));
 
         // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
         StringTokenizer st = new StringTokenizer(rsp);
 
+        InterfaceConfiguration cfg;
         try {
-            int code = Integer.parseInt(st.nextToken(" "));
-            if (code != NetdResponseCode.InterfaceGetCfgResult) {
+            try {
+                int code = Integer.parseInt(st.nextToken(" "));
+                if (code != NetdResponseCode.InterfaceGetCfgResult) {
+                    throw new IllegalStateException(
+                        String.format("Expected code %d, but got %d",
+                                NetdResponseCode.InterfaceGetCfgResult, code));
+                }
+            } catch (NumberFormatException nfe) {
                 throw new IllegalStateException(
-                    String.format("Expected code %d, but got %d",
-                            NetdResponseCode.InterfaceGetCfgResult, code));
+                        String.format("Invalid response from daemon (%s)", rsp));
             }
-        } catch (NumberFormatException nfe) {
+
+            cfg = new InterfaceConfiguration();
+            cfg.hwAddr = st.nextToken(" ");
+            try {
+                cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
+            } catch (UnknownHostException uhe) {
+                Slog.e(TAG, "Failed to parse ipaddr", uhe);
+                cfg.ipAddr = 0;
+            }
+
+            try {
+                cfg.netmask = stringToIpAddr(st.nextToken(" "));
+            } catch (UnknownHostException uhe) {
+                Slog.e(TAG, "Failed to parse netmask", uhe);
+                cfg.netmask = 0;
+            }
+            cfg.interfaceFlags = st.nextToken("]").trim() +"]";
+        } catch (NoSuchElementException nsee) {
             throw new IllegalStateException(
                     String.format("Invalid response from daemon (%s)", rsp));
         }
-
-        InterfaceConfiguration cfg = new InterfaceConfiguration();
-        cfg.hwAddr = st.nextToken(" ");
-        try {
-            cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
-        } catch (UnknownHostException uhe) {
-            Slog.e(TAG, "Failed to parse ipaddr", uhe);
-            cfg.ipAddr = 0;
-        }
-
-        try {
-            cfg.netmask = stringToIpAddr(st.nextToken(" "));
-        } catch (UnknownHostException uhe) {
-            Slog.e(TAG, "Failed to parse netmask", uhe);
-            cfg.netmask = 0;
-        }
-        cfg.interfaceFlags = st.nextToken("]").trim() +"]";
         Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
         return cfg;
     }
@@ -272,7 +290,12 @@
             String iface, InterfaceConfiguration cfg) throws IllegalStateException {
         String cmd = String.format("interface setcfg %s %s %s %s", iface,
                 intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
-        mConnector.doCommand(cmd);
+        try {
+            mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate with native daemon to interface setcfg");
+        }
     }
 
     public void shutdown() {
@@ -289,20 +312,25 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
-        ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
+        ArrayList<String> rsp;
+        try {
+            rsp = mConnector.doCommand("ipfwd status");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate with native daemon to ipfwd status");
+        }
 
         for (String line : rsp) {
-            String []tok = line.split(" ");
+            String[] tok = line.split(" ");
+            if (tok.length < 3) {
+                Slog.e(TAG, "Malformed response from native daemon: " + line);
+                return false;
+            }
+
             int code = Integer.parseInt(tok[0]);
             if (code == NetdResponseCode.IpFwdStatusResult) {
                 // 211 Forwarding <enabled/disabled>
-                if (tok.length !=2) {
-                    throw new IllegalStateException(
-                            String.format("Malformatted list entry '%s'", line));
-                }
-                if (tok[2].equals("enabled"))
-                    return true;
-                return false;
+                return "enabled".equals(tok[2]);
             } else {
                 throw new IllegalStateException(String.format("Unexpected response code %d", code));
             }
@@ -326,29 +354,45 @@
         for (String d : dhcpRange) {
             cmd += " " + d;
         }
-        mConnector.doCommand(cmd);
+
+        try {
+            mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Unable to communicate to native daemon");
+        }
     }
 
     public void stopTethering() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand("tether stop");
+        try {
+            mConnector.doCommand("tether stop");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
+        }
     }
 
     public boolean isTetheringStarted() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
-        ArrayList<String> rsp = mConnector.doCommand("tether status");
+        ArrayList<String> rsp;
+        try {
+            rsp = mConnector.doCommand("tether status");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon to get tether status");
+        }
 
         for (String line : rsp) {
-            String []tok = line.split(" ");
+            String[] tok = line.split(" ");
+            if (tok.length < 3) {
+                throw new IllegalStateException("Malformed response for tether status: " + line);
+            }
             int code = Integer.parseInt(tok[0]);
             if (code == NetdResponseCode.TetherStatusResult) {
                 // XXX: Tethering services <started/stopped> <TBD>...
-                if (tok[2].equals("started"))
-                    return true;
-                return false;
+                return "started".equals(tok[2]);
             } else {
                 throw new IllegalStateException(String.format("Unexpected response code %d", code));
             }
@@ -359,20 +403,35 @@
     public void tetherInterface(String iface) throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand("tether interface add " + iface);
+        try {
+            mConnector.doCommand("tether interface add " + iface);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for adding tether interface");
+        }
     }
 
     public void untetherInterface(String iface) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand("tether interface remove " + iface);
+        try {
+            mConnector.doCommand("tether interface remove " + iface);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for removing tether interface");
+        }
     }
 
     public String[] listTetheredInterfaces() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
-        return mConnector.doListCommand(
-                "tether interface list", NetdResponseCode.TetherInterfaceListResult);
+        try {
+            return mConnector.doListCommand(
+                    "tether interface list", NetdResponseCode.TetherInterfaceListResult);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for listing tether interfaces");
+        }
     }
 
     public void setDnsForwarders(String[] dns) throws IllegalStateException {
@@ -383,7 +442,12 @@
             for (String s : dns) {
                 cmd += " " + InetAddress.getByName(s).getHostAddress();
             }
-            mConnector.doCommand(cmd);
+            try {
+                mConnector.doCommand(cmd);
+            } catch (NativeDaemonConnectorException e) {
+                throw new IllegalStateException(
+                        "Unable to communicate to native daemon for setting tether dns");
+            }
         } catch (UnknownHostException e) {
             throw new IllegalStateException("Error resolving dns name", e);
         }
@@ -392,30 +456,50 @@
     public String[] getDnsForwarders() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
-        return mConnector.doListCommand(
-                "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
+        try {
+            return mConnector.doListCommand(
+                    "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for listing tether dns");
+        }
     }
 
     public void enableNat(String internalInterface, String externalInterface)
             throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand(
-                String.format("nat enable %s %s", internalInterface, externalInterface));
+        try {
+            mConnector.doCommand(
+                    String.format("nat enable %s %s", internalInterface, externalInterface));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for enabling NAT interface");
+        }
     }
 
     public void disableNat(String internalInterface, String externalInterface)
             throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand(
-                String.format("nat disable %s %s", internalInterface, externalInterface));
+        try {
+            mConnector.doCommand(
+                    String.format("nat disable %s %s", internalInterface, externalInterface));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for disabling NAT interface");
+        }
     }
 
     public String[] listTtys() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
-        return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
+        try {
+            return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for listing TTYs");
+        }
     }
 
     public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
@@ -430,31 +514,52 @@
                     InetAddress.getByName(dns2Addr).getHostAddress()));
         } catch (UnknownHostException e) {
             throw new IllegalStateException("Error resolving addr", e);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
         }
     }
 
     public void detachPppd(String tty) throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand(String.format("pppd detach %s", tty));
+        try {
+            mConnector.doCommand(String.format("pppd detach %s", tty));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
+        }
     }
 
     public void startUsbRNDIS() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand("usb startrndis");
+        try {
+            mConnector.doCommand("usb startrndis");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Error communicating to native daemon for starting RNDIS", e);
+        }
     }
 
     public void stopUsbRNDIS() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand("usb stoprndis");
+        try {
+            mConnector.doCommand("usb stoprndis");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Error communicating to native daemon", e);
+        }
     }
 
     public boolean isUsbRNDISStarted() throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
-        ArrayList<String> rsp = mConnector.doCommand("usb rndisstatus");
+        ArrayList<String> rsp;
+        try {
+            rsp = mConnector.doCommand("usb rndisstatus");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Error communicating to native daemon to check RNDIS status", e);
+        }
 
         for (String line : rsp) {
             String []tok = line.split(" ");
@@ -476,31 +581,35 @@
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
-        mConnector.doCommand(String.format("softap stop " + wlanIface));
-        mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
-        mConnector.doCommand(String.format("softap start " + wlanIface));
-        if (wifiConfig == null) {
-            mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
-        } else {
-            /**
-             * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
-             * argv1 - wlan interface
-             * argv2 - softap interface
-             * argv3 - SSID
-             * argv4 - Security
-             * argv5 - Key
-             * argv6 - Channel
-             * argv7 - Preamble
-             * argv8 - Max SCB
-             */
-            String str = String.format("softap set " + wlanIface + " " + softapIface +
-                                       " %s %s %s", convertQuotedString(wifiConfig.SSID),
-                                       wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
-                                       "wpa2-psk" : "open",
-                                       convertQuotedString(wifiConfig.preSharedKey));
-            mConnector.doCommand(str);
+        try {
+            mConnector.doCommand(String.format("softap stop " + wlanIface));
+            mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
+            mConnector.doCommand(String.format("softap start " + wlanIface));
+            if (wifiConfig == null) {
+                mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
+            } else {
+                /**
+                 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
+                 * argv1 - wlan interface
+                 * argv2 - softap interface
+                 * argv3 - SSID
+                 * argv4 - Security
+                 * argv5 - Key
+                 * argv6 - Channel
+                 * argv7 - Preamble
+                 * argv8 - Max SCB
+                 */
+                String str = String.format("softap set " + wlanIface + " " + softapIface +
+                                           " %s %s %s", convertQuotedString(wifiConfig.SSID),
+                                           wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
+                                           "wpa2-psk" : "open",
+                                           convertQuotedString(wifiConfig.preSharedKey));
+                mConnector.doCommand(str);
+            }
+            mConnector.doCommand(String.format("softap startap"));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Error communicating to native daemon to start softap", e);
         }
-        mConnector.doCommand(String.format("softap startap"));
     }
 
     private String convertQuotedString(String s) {
@@ -516,7 +625,12 @@
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
-        mConnector.doCommand("softap stopap");
+        try {
+            mConnector.doCommand("softap stopap");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
+                    e);
+        }
     }
 
     public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
@@ -525,15 +639,19 @@
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
         mContext.enforceCallingOrSelfPermission(
             android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
-        if (wifiConfig == null) {
-            mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
-        } else {
-            String str = String.format("softap set " + wlanIface + " " + softapIface +
-                                       " %s %s %s", convertQuotedString(wifiConfig.SSID),
-                                       wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
-                                       "wpa2-psk" : "open",
-                                       convertQuotedString(wifiConfig.preSharedKey));
-            mConnector.doCommand(str);
+        try {
+            if (wifiConfig == null) {
+                mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
+            } else {
+                String str = String.format("softap set " + wlanIface + " " + softapIface
+                        + " %s %s %s", convertQuotedString(wifiConfig.SSID),
+                        wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open",
+                        convertQuotedString(wifiConfig.preSharedKey));
+                mConnector.doCommand(str);
+            }
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException("Error communicating to native daemon to set soft AP",
+                    e);
         }
     }
 
@@ -541,9 +659,22 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
         try {
-            String rsp = mConnector.doCommand(
-                    String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
-            String []tok = rsp.split(" ");
+            String rsp;
+            try {
+                rsp = mConnector.doCommand(
+                        String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
+            } catch (NativeDaemonConnectorException e1) {
+                Slog.e(TAG, "Error communicating with native daemon", e1);
+                return -1;
+            }
+
+            String[] tok = rsp.split(" ");
+            if (tok.length < 2) {
+                Slog.e(TAG, String.format("Malformed response for reading %s interface",
+                        (rx ? "rx" : "tx")));
+                return -1;
+            }
+
             int code;
             try {
                 code = Integer.parseInt(tok[0]);
@@ -575,17 +706,34 @@
     public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand(String.format(
-                "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
+        try {
+            mConnector.doCommand(String.format(
+                    "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
+        } catch (NativeDaemonConnectorException e) {
+            Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
+        }
     }
 
     private int getInterfaceThrottle(String iface, boolean rx) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
         try {
-            String rsp = mConnector.doCommand(
-                    String.format("interface getthrottle %s %s", iface,(rx ? "rx" : "tx"))).get(0);
-            String []tok = rsp.split(" ");
+            String rsp;
+            try {
+                rsp = mConnector.doCommand(
+                        String.format("interface getthrottle %s %s", iface,
+                                (rx ? "rx" : "tx"))).get(0);
+            } catch (NativeDaemonConnectorException e) {
+                Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
+                return -1;
+            }
+
+            String[] tok = rsp.split(" ");
+            if (tok.length < 2) {
+                Slog.e(TAG, "Malformed response to getthrottle command");
+                return -1;
+            }
+
             int code;
             try {
                 code = Integer.parseInt(tok[0]);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 73d17ea..ac3b23b 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -16,9 +16,8 @@
 
 package com.android.server;
 
-import com.android.server.status.IconData;
-import com.android.server.status.NotificationData;
-import com.android.server.status.StatusBarService;
+import com.android.internal.statusbar.StatusBarNotification;
+import com.android.server.status.StatusBarManagerService;
 
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
@@ -86,7 +85,7 @@
     final IBinder mForegroundToken = new Binder();
 
     private WorkerHandler mHandler;
-    private StatusBarService mStatusBarService;
+    private StatusBarManagerService mStatusBar;
     private LightsService mLightsService;
     private LightsService.Light mBatteryLight;
     private LightsService.Light mNotificationLight;
@@ -238,8 +237,8 @@
         }
     }
 
-    private StatusBarService.NotificationCallbacks mNotificationCallbacks
-            = new StatusBarService.NotificationCallbacks() {
+    private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
+            = new StatusBarManagerService.NotificationCallbacks() {
 
         public void onSetDisabled(int status) {
             synchronized (mNotificationList) {
@@ -405,7 +404,7 @@
         }
     }
 
-    NotificationManagerService(Context context, StatusBarService statusBar,
+    NotificationManagerService(Context context, StatusBarManagerService statusBar,
             LightsService lights)
     {
         super();
@@ -417,7 +416,7 @@
         mToastQueue = new ArrayList<ToastRecord>();
         mHandler = new WorkerHandler();
 
-        mStatusBarService = statusBar;
+        mStatusBar = statusBar;
         statusBar.setNotificationCallbacks(mNotificationCallbacks);
 
         mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
@@ -705,36 +704,12 @@
             }
 
             if (notification.icon != 0) {
-                IconData icon = IconData.makeIcon(null, pkg, notification.icon,
-                                                    notification.iconLevel,
-                                                    notification.number);
-                CharSequence truncatedTicker = notification.tickerText;
-
-                // TODO: make this restriction do something smarter like never fill
-                // more than two screens.  "Why would anyone need more than 80 characters." :-/
-                final int maxTickerLen = 80;
-                if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
-                    truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
-                }
-
-                NotificationData n = new NotificationData();
-                n.pkg = pkg;
-                n.tag = tag;
-                n.id = id;
-                n.when = notification.when;
-                n.tickerText = truncatedTicker;
-                n.ongoingEvent = (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
-                if (!n.ongoingEvent && (notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
-                    n.clearable = true;
-                }
-                n.contentView = notification.contentView;
-                n.contentIntent = notification.contentIntent;
-                n.deleteIntent = notification.deleteIntent;
+                StatusBarNotification n = new StatusBarNotification(pkg, id, tag, notification);
                 if (old != null && old.statusBarKey != null) {
                     r.statusBarKey = old.statusBarKey;
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        mStatusBarService.updateIcon(r.statusBarKey, icon, n);
+                        mStatusBar.updateNotification(r.statusBarKey, n);
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
@@ -742,21 +717,19 @@
                 } else {
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        r.statusBarKey = mStatusBarService.addIcon(icon, n);
+                        r.statusBarKey = mStatusBar.addNotification(n);
                         mAttentionLight.pulse();
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
                     }
                 }
-
                 sendAccessibilityEvent(notification, pkg);
-
             } else {
                 if (old != null && old.statusBarKey != null) {
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        mStatusBarService.removeIcon(old.statusBarKey);
+                        mStatusBar.removeNotification(old.statusBarKey);
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
@@ -864,7 +837,7 @@
         if (r.notification.icon != 0) {
             long identity = Binder.clearCallingIdentity();
             try {
-                mStatusBarService.removeIcon(r.statusBarKey);
+                mStatusBar.removeNotification(r.statusBarKey);
             }
             finally {
                 Binder.restoreCallingIdentity(identity);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9d5d035..4307cdc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,7 +17,7 @@
 package com.android.server;
 
 import com.android.server.am.ActivityManagerService;
-import com.android.server.status.StatusBarService;
+import com.android.server.status.StatusBarManagerService;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 
@@ -206,7 +206,7 @@
         }
 
         DevicePolicyManagerService devicePolicy = null;
-        StatusBarService statusBar = null;
+        StatusBarManagerService statusBar = null;
         InputMethodManagerService imm = null;
         AppWidgetService appWidget = null;
         NotificationManagerService notification = null;
@@ -224,10 +224,10 @@
 
             try {
                 Slog.i(TAG, "Status Bar");
-                statusBar = new StatusBarService(context);
+                statusBar = new StatusBarManagerService(context);
                 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting StatusBarService", e);
+                Slog.e(TAG, "Failure starting StatusBarManagerService", e);
             }
 
             try {
@@ -405,12 +405,6 @@
             }
 
             try {
-                com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure installing status bar icons", e);
-            }
-
-            try {
                 Slog.i(TAG, "DiskStats Service");
                 ServiceManager.addService("diskstats", new DiskStatsService(context));
             } catch (Throwable e) {
@@ -464,6 +458,7 @@
         }
 
         // These are needed to propagate to the runnable below.
+        final StatusBarManagerService statusBarF = statusBar;
         final BatteryService batteryF = battery;
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
@@ -485,6 +480,7 @@
             public void run() {
                 Slog.i(TAG, "Making services ready");
 
+                if (statusBarF != null) statusBarF.systemReady2();
                 if (batteryF != null) batteryF.systemReady();
                 if (connectivityF != null) connectivityF.systemReady();
                 if (dockF != null) dockF.systemReady();
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 3606629d..9493161 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -545,7 +545,7 @@
             mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
         }
 
-        // Fear not: StatusBarService manages a list of requests to disable
+        // Fear not: StatusBarManagerService manages a list of requests to disable
         // features of the status bar; these are ORed together to form the
         // active disabled list. So if (for example) the device is locked and
         // the status bar should be totally disabled, the calls below will
diff --git a/services/java/com/android/server/status/IconData.java b/services/java/com/android/server/status/IconData.java
deleted file mode 100644
index fd226f9..0000000
--- a/services/java/com/android/server/status/IconData.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.util.Slog;
-
-public class IconData {
-    /**
-     * Indicates ths item represents a piece of text.
-     */
-    public static final int TEXT = 1;
-    
-    /**
-     * Indicates ths item represents an icon.
-     */
-    public static final int ICON = 2;
-
-    /**
-     * The type of this item. One of TEXT, ICON, or LEVEL_ICON.
-     */
-    public int type;
-
-    /**
-     * The slot that this icon will be in if it is not a notification
-     */
-    public String slot;
-
-    /**
-     * The package containting the icon to draw for this item. Valid if this is
-     * an ICON type.
-     */
-    public String iconPackage;
-    
-    /**
-     * The icon to draw for this item. Valid if this is an ICON type.
-     */
-    public int iconId;
-    
-    /**
-     * The level associated with the icon. Valid if this is a LEVEL_ICON type.
-     */
-    public int iconLevel;
-    
-    /**
-     * The "count" number.
-     */
-    public int number;
-
-    /**
-     * The text associated with the icon. Valid if this is a TEXT type.
-     */
-    public CharSequence text;
-
-    private IconData() {
-    }
-
-    public static IconData makeIcon(String slot,
-            String iconPackage, int iconId, int iconLevel, int number) {
-        IconData data = new IconData();
-        data.type = ICON;
-        data.slot = slot;
-        data.iconPackage = iconPackage;
-        data.iconId = iconId;
-        data.iconLevel = iconLevel;
-        data.number = number;
-        return data;
-    }
-    
-    public static IconData makeText(String slot, CharSequence text) {
-        IconData data = new IconData();
-        data.type = TEXT;
-        data.slot = slot;
-        data.text = text;
-        return data;
-    }
-
-    public void copyFrom(IconData that) {
-        this.type = that.type;
-        this.slot = that.slot;
-        this.iconPackage = that.iconPackage;
-        this.iconId = that.iconId;
-        this.iconLevel = that.iconLevel;
-        this.number = that.number;
-        this.text = that.text; // should we clone this?
-    }
-
-    public IconData clone() {
-        IconData that = new IconData();
-        that.copyFrom(this);
-        return that;
-    }
-
-    public String toString() {
-        if (this.type == TEXT) {
-            return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null")
-                    + " text='" + this.text + "')"; 
-        }
-        else if (this.type == ICON) {
-            return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null")
-                    + " package=" + this.iconPackage
-                    + " iconId=" + Integer.toHexString(this.iconId)
-                    + " iconLevel=" + this.iconLevel + ")"; 
-        }
-        else {
-            return "IconData(type=" + type + ")";
-        }
-    }
-}
diff --git a/services/java/com/android/server/status/NotificationData.java b/services/java/com/android/server/status/NotificationData.java
deleted file mode 100644
index 71f01ca..0000000
--- a/services/java/com/android/server/status/NotificationData.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.app.PendingIntent;
-import android.widget.RemoteViews;
-
-public class NotificationData {
-    public String pkg;
-    public String tag;
-    public int id;
-    public CharSequence tickerText;
-
-    public long when;
-    public boolean ongoingEvent;
-    public boolean clearable;
-
-    public RemoteViews contentView;
-    public PendingIntent contentIntent;
-
-    public PendingIntent deleteIntent;
-
-    public String toString() {
-        return "NotificationData(package=" + pkg + " id=" + id + " tickerText=" + tickerText
-                + " ongoingEvent=" + ongoingEvent + " contentIntent=" + contentIntent
-                + " deleteIntent=" + deleteIntent
-                + " clearable=" + clearable
-                + " contentView=" + contentView + " when=" + when + ")";
-    }
-}
diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java
deleted file mode 100644
index 1bb56a7..0000000
--- a/services/java/com/android/server/status/NotificationViewList.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.os.IBinder;
-import android.util.Slog;
-import android.view.View;
-import java.util.ArrayList;
-
-class NotificationViewList {
-    private ArrayList<StatusBarNotification> mOngoing = new ArrayList();
-    private ArrayList<StatusBarNotification> mLatest = new ArrayList();
-
-    NotificationViewList() {
-    }
-
-    private static final int indexInList(ArrayList<StatusBarNotification> list, NotificationData n){
-        final int N = list.size();
-        for (int i=0; i<N; i++) {
-            StatusBarNotification that = list.get(i);
-            if (that.data == n) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    int getIconIndex(NotificationData n) {
-        final int ongoingSize = mOngoing.size();
-        final int latestSize = mLatest.size();
-        if (n.ongoingEvent) {
-            int index = indexInList(mOngoing, n);
-            if (index >= 0) {
-                return latestSize + index + 1;
-            } else {
-                return -1;
-            }
-        } else {
-            return indexInList(mLatest, n) + 1;
-        }
-    }
-
-    void remove(StatusBarNotification notification) {
-        NotificationData n = notification.data;
-        int index;
-        index = indexInList(mOngoing, n);
-        if (index >= 0) {
-            mOngoing.remove(index);
-            return;
-        }
-        index = indexInList(mLatest, n);
-        if (index >= 0) {
-            mLatest.remove(index);
-            return;
-        }
-    }
-
-    ArrayList<StatusBarNotification> notificationsForPackage(String packageName) {
-        ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
-        int N = mOngoing.size();
-        for (int i=0; i<N; i++) {
-            if (matchPackage(mOngoing.get(i), packageName)) {
-                list.add(mOngoing.get(i));
-            }
-        }
-        N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            if (matchPackage(mLatest.get(i), packageName)) {
-                list.add(mLatest.get(i));
-            }
-        }
-        return list;
-    }
-    
-    private final boolean matchPackage(StatusBarNotification snb, String packageName) {
-        if (snb.data.contentIntent != null) {
-            if (snb.data.contentIntent.getTargetPackage().equals(packageName)) {
-                return true;
-            }
-        } else if (snb.data.pkg != null && snb.data.pkg.equals(packageName)) {
-            return true;
-        }
-        return false;
-    }
-    
-    private static final int indexForKey(ArrayList<StatusBarNotification> list, IBinder key) {
-        final int N = list.size();
-        for (int i=0; i<N; i++) {
-            if (list.get(i).key == key) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    StatusBarNotification get(IBinder key) {
-        int index;
-        index = indexForKey(mOngoing, key);
-        if (index >= 0) {
-            return mOngoing.get(index);
-        }
-        index = indexForKey(mLatest, key);
-        if (index >= 0) {
-            return mLatest.get(index);
-        }
-        return null;
-    }
-
-    // gets the index of the notification's view in its expanded parent view
-    int getExpandedIndex(StatusBarNotification notification) {
-        ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
-        final IBinder key = notification.key;
-        int index = 0;
-        // (the view order is backwards from this list order)
-        for (int i=list.size()-1; i>=0; i--) {
-            StatusBarNotification item = list.get(i);
-            if (item.key == key) {
-                return index;
-            }
-            if (item.view != null) {
-                index++;
-            }
-        }
-        Slog.e(StatusBarService.TAG, "Couldn't find notification in NotificationViewList.");
-        Slog.e(StatusBarService.TAG, "notification=" + notification);
-        dump(notification);
-        return 0;
-    }
-
-    void clearViews() {
-        int N = mOngoing.size();
-        for (int i=0; i<N; i++) {
-            mOngoing.get(i).view = null;
-        }
-        N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            mLatest.get(i).view = null;
-        }
-    }
-    
-    int ongoingCount() {
-        return mOngoing.size();
-    }
-
-    int latestCount() {
-        return mLatest.size();
-    }
-
-    StatusBarNotification getOngoing(int index) {
-        return mOngoing.get(index);
-    }
-
-    StatusBarNotification getLatest(int index) {
-        return mLatest.get(index);
-    }
-
-    int size() {
-        return mOngoing.size() + mLatest.size();
-    }
-
-    void add(StatusBarNotification notification) {
-        if (StatusBarService.SPEW) {
-            Slog.d(StatusBarService.TAG, "before add NotificationViewList"
-                    + " notification.data.ongoingEvent=" + notification.data.ongoingEvent);
-            dump(notification);
-        }
-
-        ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
-        long when = notification.data.when;
-        final int N = list.size();
-        int index = N;
-        for (int i=0; i<N; i++) {
-            StatusBarNotification that = list.get(i);
-            if (that.data.when > when) {
-                index = i;
-                break;
-            }
-        }
-        list.add(index, notification);
-
-        if (StatusBarService.SPEW) {
-            Slog.d(StatusBarService.TAG, "after add NotificationViewList index=" + index);
-            dump(notification);
-        }
-    }
-
-    void dump(StatusBarNotification notification) {
-        if (StatusBarService.SPEW) {
-            boolean showTime = false;
-            String s = "";
-            for (int i=0; i<mOngoing.size(); i++) {
-                StatusBarNotification that = mOngoing.get(i);
-                if (that.key == notification.key) {
-                    s += "[";
-                }
-                if (showTime) {
-                    s += that.data.when;
-                } else {
-                    s += that.data.pkg + "/" + that.data.id + "/" + that.view;
-                }
-                if (that.key == notification.key) {
-                    s += "]";
-                }
-                s += " ";
-            }
-            Slog.d(StatusBarService.TAG, "NotificationViewList ongoing: " + s);
-
-            s = "";
-            for (int i=0; i<mLatest.size(); i++) {
-                StatusBarNotification that = mLatest.get(i);
-                if (that.key == notification.key) {
-                    s += "[";
-                }
-                if (showTime) {
-                    s += that.data.when;
-                } else {
-                    s += that.data.pkg + "/" + that.data.id + "/" + that.view;
-                }
-                if (that.key == notification.key) {
-                    s += "]";
-                }
-                s += " ";
-            }
-            Slog.d(StatusBarService.TAG, "NotificationViewList latest:  " + s);
-        }
-    }
-
-    StatusBarNotification get(View view) {
-        int N = mOngoing.size();
-        for (int i=0; i<N; i++) {
-            StatusBarNotification notification = mOngoing.get(i);
-            View v = notification.view;
-            if (v == view) {
-                return notification;
-            }
-        }
-        N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            StatusBarNotification notification = mLatest.get(i);
-            View v = notification.view;
-            if (v == view) {
-                return notification;
-            }
-        }
-        return null;
-    }
-
-    void update(StatusBarNotification notification) {
-        remove(notification);
-        add(notification);
-    }
-
-    boolean hasClearableItems() {
-        int N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            if (mLatest.get(i).data.clearable) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/services/java/com/android/server/status/StatusBarException.java b/services/java/com/android/server/status/StatusBarException.java
deleted file mode 100644
index be58f59..0000000
--- a/services/java/com/android/server/status/StatusBarException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-public class StatusBarException extends RuntimeException {
-    StatusBarException(String msg) {
-        super(msg);
-    }
-}
diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java
deleted file mode 100644
index f77b550..0000000
--- a/services/java/com/android/server/status/StatusBarIcon.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-class StatusBarIcon {
-    // TODO: get this from a resource
-    private static final int ICON_GAP = 8;
-    private static final int ICON_WIDTH = 25;
-    private static final int ICON_HEIGHT = 25;
-
-    public View view;
-
-    IconData mData;
-    
-    private TextView mTextView;
-    private AnimatedImageView mImageView;
-    private TextView mNumberView;
-
-    public StatusBarIcon(Context context, IconData data, ViewGroup parent) {
-        mData = data.clone();
-
-        switch (data.type) {
-            case IconData.TEXT: {
-                TextView t;
-                t = new TextView(context, null, com.android.internal.R.style.TextAppearance_StatusBar_Icon);
-                mTextView = t;
-                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                        LinearLayout.LayoutParams.WRAP_CONTENT,
-                        LinearLayout.LayoutParams.MATCH_PARENT);
-                t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
-                t.setPadding(6, 0, 0, 0);
-                t.setLayoutParams(layoutParams);
-                t.setText(data.text);
-                this.view = t;
-                break;
-            }
-
-            case IconData.ICON: {
-                // container
-                LayoutInflater inflater = (LayoutInflater)context.getSystemService(
-                                                Context.LAYOUT_INFLATER_SERVICE);
-                View v = inflater.inflate(com.android.internal.R.layout.status_bar_icon, parent, false);
-                this.view = v;
-
-                // icon
-                AnimatedImageView im = (AnimatedImageView)v.findViewById(com.android.internal.R.id.image);
-                im.setImageDrawable(getIcon(context, data));
-                im.setImageLevel(data.iconLevel);
-                mImageView = im;
-
-                // number
-                TextView nv = (TextView)v.findViewById(com.android.internal.R.id.number);
-                mNumberView = nv;
-                if (data.number > 0) {
-                    nv.setText("" + data.number);
-                    nv.setVisibility(View.VISIBLE);
-                } else {
-                    nv.setVisibility(View.GONE);
-                }
-                break;
-            }
-        }
-    }
-
-    public void update(Context context, IconData data) throws StatusBarException {
-        if (mData.type != data.type) {
-            throw new StatusBarException("status bar entry type can't change");
-        }
-        switch (data.type) {
-        case IconData.TEXT:
-            if (!TextUtils.equals(mData.text, data.text)) {
-                TextView tv = mTextView;
-                tv.setText(data.text);
-            }
-            break;
-        case IconData.ICON:
-            if (((mData.iconPackage != null && data.iconPackage != null)
-                        && !mData.iconPackage.equals(data.iconPackage))
-                    || mData.iconId != data.iconId
-                    || mData.iconLevel != data.iconLevel) {
-                ImageView im = mImageView;
-                im.setImageDrawable(getIcon(context, data));
-                im.setImageLevel(data.iconLevel);
-            }
-            if (mData.number != data.number) {
-                TextView nv = mNumberView;
-                if (data.number > 0) {
-                    nv.setText("" + data.number);
-                } else {
-                    nv.setText("");
-                }
-            }
-            break;
-        }
-        mData.copyFrom(data);
-    }
-
-    public void update(int number) {
-        if (mData.number != number) {
-            TextView nv = mNumberView;
-            if (number > 0) {
-                nv.setText("" + number);
-            } else {
-                nv.setText("");
-            }
-        }
-        mData.number = number;
-    }
-
-
-    /**
-     * Returns the right icon to use for this item, respecting the iconId and
-     * iconPackage (if set)
-     * 
-     * @param context Context to use to get resources if iconPackage is not set
-     * @return Drawable for this item, or null if the package or item could not
-     *         be found
-     */
-    static Drawable getIcon(Context context, IconData data) {
-
-        Resources r = null;
-
-        if (data.iconPackage != null) {
-            try {
-                r = context.getPackageManager().getResourcesForApplication(data.iconPackage);
-            } catch (PackageManager.NameNotFoundException ex) {
-                Slog.e(StatusBarService.TAG, "Icon package not found: " + data.iconPackage, ex);
-                return null;
-            }
-        } else {
-            r = context.getResources();
-        }
-
-        if (data.iconId == 0) {
-            Slog.w(StatusBarService.TAG, "No icon ID for slot " + data.slot);
-            return null;
-        }
-        
-        try {
-            return r.getDrawable(data.iconId);
-        } catch (RuntimeException e) {
-            Slog.w(StatusBarService.TAG, "Icon not found in "
-                  + (data.iconPackage != null ? data.iconId : "<system>")
-                  + ": " + Integer.toHexString(data.iconId));
-        }
-
-        return null;
-    }
-
-    int getNumber() {
-        return mData.number;
-    }
-}
-
diff --git a/services/java/com/android/server/status/StatusBarManagerService.java b/services/java/com/android/server/status/StatusBarManagerService.java
new file mode 100644
index 0000000..0af1ebb
--- /dev/null
+++ b/services/java/com/android/server/status/StatusBarManagerService.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.status;
+
+import android.app.PendingIntent;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A note on locking:  We rely on the fact that calls onto mBar are oneway or
+ * if they are local, that they just enqueue messages to not deadlock.
+ */
+public class StatusBarManagerService extends IStatusBarService.Stub
+{
+    static final String TAG = "StatusBarManagerService";
+    static final boolean SPEW = true;
+
+    public static final String ACTION_STATUSBAR_START
+            = "com.android.internal.policy.statusbar.START";
+
+    final Context mContext;
+    Handler mHandler = new Handler();
+    NotificationCallbacks mNotificationCallbacks;
+    volatile IStatusBar mBar;
+    StatusBarIconList mIcons = new StatusBarIconList();
+    HashMap<IBinder,StatusBarNotification> mNotifications
+            = new HashMap<IBinder,StatusBarNotification>();
+
+    // for disabling the status bar
+    ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+    int mDisabled = 0;
+
+    private class DisableRecord implements IBinder.DeathRecipient {
+        String pkg;
+        int what;
+        IBinder token;
+
+        public void binderDied() {
+            Slog.i(TAG, "binder died for pkg=" + pkg);
+            disable(0, token, pkg);
+            token.unlinkToDeath(this, 0);
+        }
+    }
+
+    public interface NotificationCallbacks {
+        void onSetDisabled(int status);
+        void onClearAll();
+        void onNotificationClick(String pkg, String tag, int id);
+        void onPanelRevealed();
+    }
+
+    /**
+     * Construct the service, add the status bar view to the window manager
+     */
+    public StatusBarManagerService(Context context) {
+        mContext = context;
+
+        final Resources res = context.getResources();
+        mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.status_bar_icon_order));
+    }
+
+    public void setNotificationCallbacks(NotificationCallbacks listener) {
+        mNotificationCallbacks = listener;
+    }
+
+    // ================================================================================
+    // Constructing the view
+    // ================================================================================
+
+    public void systemReady() {
+    }
+
+    public void systemReady2() {
+        // Start the status bar app
+        Intent intent = new Intent(ACTION_STATUSBAR_START);
+        mContext.sendBroadcast(intent /** permission  **/);
+    }
+
+    // ================================================================================
+    // From IStatusBarService
+    // ================================================================================
+    public void expand() {
+        enforceExpandStatusBar();
+
+        if (mBar != null) {
+            try {
+                mBar.animateExpand();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    public void collapse() {
+        enforceExpandStatusBar();
+
+        if (mBar != null) {
+            try {
+                mBar.animateCollapse();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    public void disable(int what, IBinder token, String pkg) {
+        enforceStatusBar();
+
+        // It's important that the the callback and the call to mBar get done
+        // in the same order when multiple threads are calling this function
+        // so they are paired correctly.  The messages on the handler will be
+        // handled in the order they were enqueued, but will be outside the lock.
+        synchronized (mDisableRecords) {
+            manageDisableListLocked(what, token, pkg);
+            final int net = gatherDisableActionsLocked();
+            Slog.d(TAG, "disable... net=0x" + Integer.toHexString(net));
+            if (net != mDisabled) {
+                mDisabled = net;
+                mHandler.post(new Runnable() {
+                        public void run() {
+                            mNotificationCallbacks.onSetDisabled(net);
+                        }
+                    });
+                if (mBar != null) {
+                    try {
+                        mBar.disable(net);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    }
+
+    public void setIcon(String slot, String iconPackage, int iconId, int iconLevel) {
+        enforceStatusBar();
+
+        synchronized (mIcons) {
+            int index = mIcons.getSlotIndex(slot);
+            if (index < 0) {
+                throw new SecurityException("invalid status bar icon slot: " + slot);
+            }
+
+            StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel);
+            //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
+            mIcons.setIcon(index, icon);
+
+            if (mBar != null) {
+                try {
+                    mBar.setIcon(index, icon);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    public void setIconVisibility(String slot, boolean visible) {
+        enforceStatusBar();
+
+        synchronized (mIcons) {
+            int index = mIcons.getSlotIndex(slot);
+            if (index < 0) {
+                throw new SecurityException("invalid status bar icon slot: " + slot);
+            }
+
+            StatusBarIcon icon = mIcons.getIcon(index);
+            if (icon == null) {
+                return;
+            }
+
+            if (icon.visible != visible) {
+                icon.visible = visible;
+
+                if (mBar != null) {
+                    try {
+                        mBar.setIcon(index, icon);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    }
+
+    public void removeIcon(String slot) {
+        enforceStatusBar();
+
+        synchronized (mIcons) {
+            int index = mIcons.getSlotIndex(slot);
+            if (index < 0) {
+                throw new SecurityException("invalid status bar icon slot: " + slot);
+            }
+
+            mIcons.removeIcon(index);
+
+            if (mBar != null) {
+                try {
+                    mBar.removeIcon(index);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    private void enforceStatusBar() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
+                "StatusBarManagerService");
+    }
+
+    private void enforceExpandStatusBar() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR,
+                "StatusBarManagerService");
+    }
+
+
+    // ================================================================================
+    // Callbacks from the status bar service.
+    // ================================================================================
+    public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
+            List<IBinder> notificationKeys, List<StatusBarNotification> notifications) {
+        Slog.i(TAG, "registerStatusBar bar=" + bar);
+        mBar = bar;
+        synchronized (mIcons) {
+            iconList.copyFrom(mIcons);
+        }
+        synchronized (mNotifications) {
+            for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {
+                notificationKeys.add(e.getKey());
+                notifications.add(e.getValue());
+            }
+        }
+    }
+
+    /**
+     * The status bar service should call this when the user changes whether
+     * the status bar is visible or not.
+     */
+    public void visibilityChanged(boolean visible) {
+        //Slog.d(TAG, "visibilityChanged visible=" + visible);
+    }
+
+    public void onNotificationClick(String pkg, String tag, int id) {
+        mNotificationCallbacks.onNotificationClick(pkg, tag, id);
+    }
+
+    public void onClearAllNotifications() {
+        mNotificationCallbacks.onClearAll();
+    }
+
+    // ================================================================================
+    // Callbacks for NotificationManagerService.
+    // ================================================================================
+    public IBinder addNotification(StatusBarNotification notification) {
+        synchronized (mNotifications) {
+            IBinder key = new Binder();
+            mNotifications.put(key, notification);
+            if (mBar != null) {
+                try {
+                    mBar.addNotification(key, notification);
+                } catch (RemoteException ex) {
+                }
+            }
+            return key;
+        }
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        synchronized (mNotifications) {
+            if (!mNotifications.containsKey(key)) {
+                throw new IllegalArgumentException("updateNotification key not found: " + key);
+            }
+            mNotifications.put(key, notification);
+            if (mBar != null) {
+                try {
+                    mBar.updateNotification(key, notification);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    public void removeNotification(IBinder key) {
+        synchronized (mNotifications) {
+            final StatusBarNotification n = mNotifications.remove(key);
+            if (n == null) {
+                throw new IllegalArgumentException("removeNotification key not found: " + key);
+            }
+            if (mBar != null) {
+                try {
+                    mBar.removeNotification(key);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    // ================================================================================
+    // Can be called from any thread
+    // ================================================================================
+
+    // lock on mDisableRecords
+    void manageDisableListLocked(int what, IBinder token, String pkg) {
+        if (SPEW) {
+            Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
+        }
+        // update the list
+        synchronized (mDisableRecords) {
+            final int N = mDisableRecords.size();
+            DisableRecord tok = null;
+            int i;
+            for (i=0; i<N; i++) {
+                DisableRecord t = mDisableRecords.get(i);
+                if (t.token == token) {
+                    tok = t;
+                    break;
+                }
+            }
+            if (what == 0 || !token.isBinderAlive()) {
+                if (tok != null) {
+                    mDisableRecords.remove(i);
+                    tok.token.unlinkToDeath(tok, 0);
+                }
+            } else {
+                if (tok == null) {
+                    tok = new DisableRecord();
+                    try {
+                        token.linkToDeath(tok, 0);
+                    }
+                    catch (RemoteException ex) {
+                        return; // give up
+                    }
+                    mDisableRecords.add(tok);
+                }
+                tok.what = what;
+                tok.token = token;
+                tok.pkg = pkg;
+            }
+        }
+    }
+
+    // lock on mDisableRecords
+    int gatherDisableActionsLocked() {
+        final int N = mDisableRecords.size();
+        // gather the new net flags
+        int net = 0;
+        for (int i=0; i<N; i++) {
+            net |= mDisableRecords.get(i).what;
+        }
+        return net;
+    }
+
+    // ================================================================================
+    // Always called from UI thread
+    // ================================================================================
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump StatusBar from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mIcons) {
+            mIcons.dump(pw);
+        }
+
+        synchronized (mNotifications) {
+            int i=0;
+            pw.println("Notification list:");
+            for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {
+                pw.printf("  %2d: %s\n", i, e.getValue().toString());
+                i++;
+            }
+        }
+
+        synchronized (mDisableRecords) {
+            final int N = mDisableRecords.size();
+            pw.println("  mDisableRecords.size=" + N
+                    + " mDisabled=0x" + Integer.toHexString(mDisabled));
+            for (int i=0; i<N; i++) {
+                DisableRecord tok = mDisableRecords.get(i);
+                pw.println("    [" + i + "] what=0x" + Integer.toHexString(tok.what)
+                                + " pkg=" + tok.pkg + " token=" + tok.token);
+            }
+        }
+    }
+
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    private boolean mPanelSlightlyVisible;
+    void panelSlightlyVisible(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            if (visible) {
+                // tell the notification manager to turn off the lights.
+                mNotificationCallbacks.onPanelRevealed();
+            }
+        }
+    }
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                collapse();
+            }
+            /*
+            else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
+                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
+                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
+            }
+            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                updateResources();
+            }
+            */
+        }
+    };
+
+}
diff --git a/services/java/com/android/server/status/StatusBarNotification.java b/services/java/com/android/server/status/StatusBarNotification.java
deleted file mode 100644
index e5773f7..0000000
--- a/services/java/com/android/server/status/StatusBarNotification.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.os.IBinder;
-import android.view.View;
-
-class StatusBarNotification {
-    IBinder key;
-    NotificationData data;
-    View view;
-    View contentView;
-}
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
deleted file mode 100644
index cab2662..0000000
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothPbap;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.TypedArray;
-import android.graphics.PixelFormat;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.location.LocationManager;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.NetworkInfo;
-import android.net.Uri;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.storage.StorageManager;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.text.format.DateFormat;
-import android.text.style.CharacterStyle;
-import android.text.style.RelativeSizeSpan;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.StyleSpan;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.util.Slog;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.EriInfo;
-import com.android.internal.telephony.cdma.TtyIntent;
-import com.android.server.am.BatteryStatsService;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * This class contains all of the policy about which icons are installed in the status
- * bar at boot time.  In reality, it should go into the android.policy package, but
- * putting it here is the first step from extracting it.
- */
-public class StatusBarPolicy {
-    private static final String TAG = "StatusBarPolicy";
-
-    private static StatusBarPolicy sInstance;
-
-    // message codes for the handler
-    private static final int EVENT_BATTERY_CLOSE = 4;
-
-    private static final int AM_PM_STYLE_NORMAL  = 0;
-    private static final int AM_PM_STYLE_SMALL   = 1;
-    private static final int AM_PM_STYLE_GONE    = 2;
-
-    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
-
-    private final Context mContext;
-    private final StatusBarService mService;
-    private final Handler mHandler = new StatusBarHandler();
-    private final IBatteryStats mBatteryStats;
-
-    // clock
-    private Calendar mCalendar;
-    private String mClockFormatString;
-    private SimpleDateFormat mClockFormat;
-    private IBinder mClockIcon;
-    private IconData mClockData;
-
-    // storage
-    private StorageManager mStorageManager;
-
-    // battery
-    private IBinder mBatteryIcon;
-    private IconData mBatteryData;
-    private boolean mBatteryFirst = true;
-    private boolean mBatteryPlugged;
-    private int mBatteryLevel;
-    private AlertDialog mLowBatteryDialog;
-    private TextView mBatteryLevelTextView;
-    private View mBatteryView;
-    private int mBatteryViewSequence;
-    private boolean mBatteryShowLowOnEndCall = false;
-    private static final boolean SHOW_LOW_BATTERY_WARNING = true;
-    private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
-
-    // phone
-    private TelephonyManager mPhone;
-    private IBinder mPhoneIcon;
-
-    //***** Signal strength icons
-    private IconData mPhoneData;
-    //GSM/UMTS
-    private static final int[] sSignalImages = new int[] {
-        com.android.internal.R.drawable.stat_sys_signal_0,
-        com.android.internal.R.drawable.stat_sys_signal_1,
-        com.android.internal.R.drawable.stat_sys_signal_2,
-        com.android.internal.R.drawable.stat_sys_signal_3,
-        com.android.internal.R.drawable.stat_sys_signal_4
-    };
-    private static final int[] sSignalImages_r = new int[] {
-        com.android.internal.R.drawable.stat_sys_r_signal_0,
-        com.android.internal.R.drawable.stat_sys_r_signal_1,
-        com.android.internal.R.drawable.stat_sys_r_signal_2,
-        com.android.internal.R.drawable.stat_sys_r_signal_3,
-        com.android.internal.R.drawable.stat_sys_r_signal_4
-    };
-    private static final int[] sRoamingIndicatorImages_cdma = new int[] {
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
-        // 1 is Standard Roaming Indicator OFF
-        // TODO T: image never used, remove and put 0 instead?
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 2 is Standard Roaming Indicator FLASHING
-        // TODO T: image never used, remove and put 0 instead?
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 3-12 Standard ERI
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 13-63 Reserved for Standard ERI
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 64-127 Reserved for Non Standard (Operator Specific) ERI
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
-
-        // 128-255 Reserved
-    };
-
-    //***** Data connection icons
-    private int[] mDataIconList = sDataNetType_g;
-    //GSM/UMTS
-    private static final int[] sDataNetType_g = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_g,
-            com.android.internal.R.drawable.stat_sys_data_in_g,
-            com.android.internal.R.drawable.stat_sys_data_out_g,
-            com.android.internal.R.drawable.stat_sys_data_inandout_g,
-        };
-    private static final int[] sDataNetType_3g = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_3g,
-            com.android.internal.R.drawable.stat_sys_data_in_3g,
-            com.android.internal.R.drawable.stat_sys_data_out_3g,
-            com.android.internal.R.drawable.stat_sys_data_inandout_3g,
-        };
-    private static final int[] sDataNetType_e = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_e,
-            com.android.internal.R.drawable.stat_sys_data_in_e,
-            com.android.internal.R.drawable.stat_sys_data_out_e,
-            com.android.internal.R.drawable.stat_sys_data_inandout_e,
-        };
-    //3.5G
-    private static final int[] sDataNetType_h = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_h,
-            com.android.internal.R.drawable.stat_sys_data_in_h,
-            com.android.internal.R.drawable.stat_sys_data_out_h,
-            com.android.internal.R.drawable.stat_sys_data_inandout_h,
-    };
-
-    //CDMA
-    // Use 3G icons for EVDO data and 1x icons for 1XRTT data
-    private static final int[] sDataNetType_1x = new int[] {
-        com.android.internal.R.drawable.stat_sys_data_connected_1x,
-        com.android.internal.R.drawable.stat_sys_data_in_1x,
-        com.android.internal.R.drawable.stat_sys_data_out_1x,
-        com.android.internal.R.drawable.stat_sys_data_inandout_1x,
-    };
-
-    // Assume it's all good unless we hear otherwise.  We don't always seem
-    // to get broadcasts that it *is* there.
-    IccCard.State mSimState = IccCard.State.READY;
-    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-    int mDataState = TelephonyManager.DATA_DISCONNECTED;
-    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
-    ServiceState mServiceState;
-    SignalStrength mSignalStrength;
-
-    // data connection
-    private IBinder mDataIcon;
-    private IconData mDataData;
-    private boolean mDataIconVisible;
-    private boolean mHspaDataDistinguishable;
-
-    // ringer volume
-    private IBinder mVolumeIcon;
-    private IconData mVolumeData;
-    private boolean mVolumeVisible;
-
-    // bluetooth device status
-    private IBinder mBluetoothIcon;
-    private IconData mBluetoothData;
-    private int mBluetoothHeadsetState;
-    private boolean mBluetoothA2dpConnected;
-    private int mBluetoothPbapState;
-    private boolean mBluetoothEnabled;
-
-    // wifi
-    private static final int[] sWifiSignalImages = new int[] {
-            com.android.internal.R.drawable.stat_sys_wifi_signal_1,
-            com.android.internal.R.drawable.stat_sys_wifi_signal_2,
-            com.android.internal.R.drawable.stat_sys_wifi_signal_3,
-            com.android.internal.R.drawable.stat_sys_wifi_signal_4,
-        };
-    private static final int sWifiTemporarilyNotConnectedImage =
-            com.android.internal.R.drawable.stat_sys_wifi_signal_0;
-
-    private int mLastWifiSignalLevel = -1;
-    private boolean mIsWifiConnected = false;
-    private IBinder mWifiIcon;
-    private IconData mWifiData;
-
-    // gps
-    private IBinder mGpsIcon;
-    private IconData mGpsEnabledIconData;
-    private IconData mGpsFixIconData;
-
-    // alarm clock
-    // Icon lit when clock is set
-    private IBinder mAlarmClockIcon;
-    private IconData mAlarmClockIconData;
-
-    // sync state
-    // If sync is active the SyncActive icon is displayed. If sync is not active but
-    // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
-    private IBinder mSyncActiveIcon;
-    private IBinder mSyncFailingIcon;
-
-    // TTY mode
-    // Icon lit when TTY mode is enabled
-    private IBinder mTTYModeIcon;
-    private IconData mTTYModeEnableIconData;
-
-    // Cdma Roaming Indicator, ERI
-    private IBinder mCdmaRoamingIndicatorIcon;
-    private IconData mCdmaRoamingIndicatorIconData;
-
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_TIME_TICK)) {
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-                updateBattery(intent);
-            }
-            else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
-                String tz = intent.getStringExtra("time-zone");
-                mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
-                if (mClockFormat != null) {
-                    mClockFormat.setTimeZone(mCalendar.getTimeZone());
-                }
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
-                updateAlarm(intent);
-            }
-            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
-                updateSyncState(intent);
-            }
-            else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
-                onBatteryLow(intent);
-            }
-            else if (action.equals(Intent.ACTION_BATTERY_OKAY)
-                    || action.equals(Intent.ACTION_POWER_CONNECTED)) {
-                onBatteryOkay(intent);
-            }
-            else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
-                    action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
-                    action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
-                    action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
-                updateBluetooth(intent);
-            }
-            else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
-                    action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
-                    action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-                updateWifi(intent);
-            }
-            else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) ||
-                    action.equals(LocationManager.GPS_FIX_CHANGE_ACTION)) {
-                updateGps(intent);
-            }
-            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
-                    action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
-                updateVolume();
-            }
-            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-                updateSimState(intent);
-            }
-            else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
-                updateTTY(intent);
-            }
-        }
-    };
-
-    private StatusBarPolicy(Context context, StatusBarService service) {
-        mContext = context;
-        mService = service;
-        mSignalStrength = new SignalStrength();
-        mBatteryStats = BatteryStatsService.getService();
-
-        // clock
-        mCalendar = Calendar.getInstance(TimeZone.getDefault());
-        mClockData = IconData.makeText("clock", "");
-        mClockIcon = service.addIcon(mClockData, null);
-        updateClock();
-
-        // storage
-        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
-        mStorageManager.registerListener(
-                new com.android.server.status.StorageNotification(context));
-
-        // battery
-        mBatteryData = IconData.makeIcon("battery",
-                null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
-        mBatteryIcon = service.addIcon(mBatteryData, null);
-
-        // phone_signal
-        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        mPhoneData = IconData.makeIcon("phone_signal",
-                null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
-        mPhoneIcon = service.addIcon(mPhoneData, null);
-
-        // register for phone state notifications.
-        ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
-                .listen(mPhoneStateListener,
-                          PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_CALL_STATE
-                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
-
-        // data_connection
-        mDataData = IconData.makeIcon("data_connection",
-                null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
-        mDataIcon = service.addIcon(mDataData, null);
-        service.setIconVisibility(mDataIcon, false);
-
-        // wifi
-        mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
-        mWifiIcon = service.addIcon(mWifiData, null);
-        service.setIconVisibility(mWifiIcon, false);
-        // wifi will get updated by the sticky intents
-
-        // TTY status
-        mTTYModeEnableIconData = IconData.makeIcon("tty",
-                null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
-        mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
-        service.setIconVisibility(mTTYModeIcon, false);
-
-        // Cdma Roaming Indicator, ERI
-        mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
-                null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
-        mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
-        service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-
-        // bluetooth status
-        mBluetoothData = IconData.makeIcon("bluetooth",
-                null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
-        mBluetoothIcon = service.addIcon(mBluetoothData, null);
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            mBluetoothEnabled = adapter.isEnabled();
-        } else {
-            mBluetoothEnabled = false;
-        }
-        mBluetoothA2dpConnected = false;
-        mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
-        mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
-        mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
-
-        // Gps status
-        mGpsEnabledIconData = IconData.makeIcon("gps",
-                null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
-        mGpsFixIconData = IconData.makeIcon("gps",
-                null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
-        mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
-        service.setIconVisibility(mGpsIcon, false);
-
-        // Alarm clock
-        mAlarmClockIconData = IconData.makeIcon(
-                "alarm_clock",
-                null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
-        mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
-        service.setIconVisibility(mAlarmClockIcon, false);
-
-        // Sync state
-        mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
-                null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
-        mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
-                null, R.drawable.stat_notify_sync_error, 0, 0), null);
-        service.setIconVisibility(mSyncActiveIcon, false);
-        service.setIconVisibility(mSyncFailingIcon, false);
-
-        // volume
-        mVolumeData = IconData.makeIcon("volume",
-                null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
-        mVolumeIcon = service.addIcon(mVolumeData, null);
-        service.setIconVisibility(mVolumeIcon, false);
-        updateVolume();
-
-        IntentFilter filter = new IntentFilter();
-
-        // Register for Intent broadcasts for...
-        filter.addAction(Intent.ACTION_TIME_TICK);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(Intent.ACTION_BATTERY_LOW);
-        filter.addAction(Intent.ACTION_BATTERY_OKAY);
-        filter.addAction(Intent.ACTION_POWER_CONNECTED);
-        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        filter.addAction(Intent.ACTION_ALARM_CHANGED);
-        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
-        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
-        filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
-        filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
-        filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
-        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
-
-        // load config to determine if to distinguish Hspa data icon
-        try {
-            mHspaDataDistinguishable = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_hspa_data_distinguishable);
-        } catch (Exception e) {
-            mHspaDataDistinguishable = false;
-        }
-    }
-
-    public static void installIcons(Context context, StatusBarService service) {
-        sInstance = new StatusBarPolicy(context, service);
-    }
-
-    private final CharSequence getSmallTime() {
-        boolean b24 = DateFormat.is24HourFormat(mContext);
-        int res;
-
-        if (b24) {
-            res = R.string.twenty_four_hour_time_format;
-        } else {
-            res = R.string.twelve_hour_time_format;
-        }
-
-        final char MAGIC1 = '\uEF00';
-        final char MAGIC2 = '\uEF01';
-
-        SimpleDateFormat sdf;
-        String format = mContext.getString(res);
-        if (!format.equals(mClockFormatString)) {
-            /*
-             * Search for an unquoted "a" in the format string, so we can
-             * add dummy characters around it to let us find it again after
-             * formatting and change its size.
-             */
-            if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
-                int a = -1;
-                boolean quoted = false;
-                for (int i = 0; i < format.length(); i++) {
-                    char c = format.charAt(i);
-
-                    if (c == '\'') {
-                        quoted = !quoted;
-                    }
-
-                    if (!quoted && c == 'a') {
-                        a = i;
-                        break;
-                    }
-                }
-
-                if (a >= 0) {
-                    // Move a back so any whitespace before the AM/PM is also in the alternate size.
-                    final int b = a;
-                    while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
-                        a--;
-                    }
-                    format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
-                            + "a" + MAGIC2 + format.substring(b + 1);
-                }
-            }
-
-            mClockFormat = sdf = new SimpleDateFormat(format);
-            mClockFormatString = format;
-        } else {
-            sdf = mClockFormat;
-        }
-        String result = sdf.format(mCalendar.getTime());
-
-        if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
-            int magic1 = result.indexOf(MAGIC1);
-            int magic2 = result.indexOf(MAGIC2);
-
-            if (magic1 >= 0 && magic2 > magic1) {
-                SpannableStringBuilder formatted = new SpannableStringBuilder(result);
-
-                if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
-                    formatted.delete(magic1, magic2+1);
-                } else {
-                    if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
-                        CharacterStyle style = new RelativeSizeSpan(0.7f);
-                        formatted.setSpan(style, magic1, magic2,
-                                          Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
-                    }
-
-                    formatted.delete(magic2, magic2 + 1);
-                    formatted.delete(magic1, magic1 + 1);
-                }
-
-                return formatted;
-            }
-        }
- 
-        return result;
-    }
-
-    private final void updateClock() {
-        mCalendar.setTimeInMillis(System.currentTimeMillis());
-        mClockData.text = getSmallTime();
-        mService.updateIcon(mClockIcon, mClockData, null);
-    }
-
-    private final void updateAlarm(Intent intent) {
-        boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
-        mService.setIconVisibility(mAlarmClockIcon, alarmSet);
-    }
-
-    private final void updateSyncState(Intent intent) {
-        boolean isActive = intent.getBooleanExtra("active", false);
-        boolean isFailing = intent.getBooleanExtra("failing", false);
-        mService.setIconVisibility(mSyncActiveIcon, isActive);
-        // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
-        //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
-    }
-
-    private final void updateBattery(Intent intent) {
-        mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
-        mBatteryData.iconLevel = intent.getIntExtra("level", 0);
-        mService.updateIcon(mBatteryIcon, mBatteryData, null);
-
-        boolean plugged = intent.getIntExtra("plugged", 0) != 0;
-        int level = intent.getIntExtra("level", -1);
-        if (false) {
-            Slog.d(TAG, "updateBattery level=" + level
-                    + " plugged=" + plugged
-                    + " mBatteryPlugged=" + mBatteryPlugged
-                    + " mBatteryLevel=" + mBatteryLevel
-                    + " mBatteryFirst=" + mBatteryFirst);
-        }
-
-        boolean oldPlugged = mBatteryPlugged;
-
-        mBatteryPlugged = plugged;
-        mBatteryLevel = level;
-
-        if (mBatteryFirst) {
-            mBatteryFirst = false;
-        }
-        /*
-         * No longer showing the battery view because it draws attention away
-         * from the USB storage notification. We could still show it when
-         * connected to a brick, but that could lead to the user into thinking
-         * the device does not charge when plugged into USB (since he/she would
-         * not see the same battery screen on USB as he sees on brick).
-         */
-        /* else {
-            if (plugged && !oldPlugged) {
-                showBatteryView();
-            }
-        }
-        */
-        if (false) {
-            Slog.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
-        }
-    }
-
-    private void onBatteryLow(Intent intent) {
-        if (SHOW_LOW_BATTERY_WARNING) {
-            if (false) {
-                Slog.d(TAG, "mPhoneState=" + mPhoneState
-                      + " mLowBatteryDialog=" + mLowBatteryDialog
-                      + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
-            }
-
-            if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
-                showLowBatteryWarning();
-            } else {
-                mBatteryShowLowOnEndCall = true;
-            }
-        }
-    }
-
-    private void onBatteryOkay(Intent intent) {
-        if (mLowBatteryDialog != null
-                && SHOW_LOW_BATTERY_WARNING) {
-            mLowBatteryDialog.dismiss();
-            mBatteryShowLowOnEndCall = false;
-        }
-    }
-
-    private void showBatteryView() {
-        closeLastBatteryView();
-        if (mLowBatteryDialog != null) {
-            mLowBatteryDialog.dismiss();
-        }
-
-        int level = mBatteryLevel;
-
-        View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
-        mBatteryView = v;
-        int pixelFormat = PixelFormat.TRANSLUCENT;
-        Drawable bg = v.getBackground();
-        if (bg != null) {
-            pixelFormat = bg.getOpacity();
-        }
-
-        int flags =  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                | WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-
-        if (!mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_sf_slowBlur)) {
-            flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
-        }
-
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_TOAST,
-                flags, pixelFormat);
-
-        // Get the dim amount from the theme
-        TypedArray a = mContext.obtainStyledAttributes(
-                com.android.internal.R.styleable.Theme);
-        lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
-        a.recycle();
-
-        lp.setTitle("Battery");
-
-        TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
-        levelTextView.setText(mContext.getString(
-                    com.android.internal.R.string.battery_status_text_percent_format, level));
-
-        setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
-        setBatteryLevel(v, com.android.internal.R.id.level, level,
-                com.android.internal.R.drawable.battery_charge_fill, level);
-
-        WindowManagerImpl.getDefault().addView(v, lp);
-
-        scheduleCloseBatteryView();
-    }
-
-    private void setBatteryLevel(View parent, int id, int height, int background, int level) {
-        ImageView v = (ImageView)parent.findViewById(id);
-        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
-        lp.weight = height;
-        if (background != 0) {
-            v.setBackgroundResource(background);
-            Drawable bkg = v.getBackground();
-            bkg.setLevel(level);
-        }
-    }
-
-    private void showLowBatteryWarning() {
-        closeLastBatteryView();
-
-        // Show exact battery level.
-        CharSequence levelText = mContext.getString(
-                    com.android.internal.R.string.battery_low_percent_format, mBatteryLevel);
-
-        if (mBatteryLevelTextView != null) {
-            mBatteryLevelTextView.setText(levelText);
-        } else {
-            View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
-            mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
-
-            mBatteryLevelTextView.setText(levelText);
-
-            AlertDialog.Builder b = new AlertDialog.Builder(mContext);
-                b.setCancelable(true);
-                b.setTitle(com.android.internal.R.string.battery_low_title);
-                b.setView(v);
-                b.setIcon(android.R.drawable.ic_dialog_alert);
-                b.setPositiveButton(android.R.string.ok, null);
-
-                final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                        | Intent.FLAG_ACTIVITY_NO_HISTORY);
-                if (intent.resolveActivity(mContext.getPackageManager()) != null) {
-                    b.setNegativeButton(com.android.internal.R.string.battery_low_why,
-                            new DialogInterface.OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            mContext.startActivity(intent);
-                            if (mLowBatteryDialog != null) {
-                                mLowBatteryDialog.dismiss();
-                            }
-                        }
-                    });
-                }
-
-            AlertDialog d = b.create();
-            d.setOnDismissListener(mLowBatteryListener);
-            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            d.show();
-            mLowBatteryDialog = d;
-        }
-
-        final ContentResolver cr = mContext.getContentResolver();
-        if (Settings.System.getInt(cr,
-                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
-        {
-            final String soundPath = Settings.System.getString(cr,
-                Settings.System.LOW_BATTERY_SOUND);
-            if (soundPath != null) {
-                final Uri soundUri = Uri.parse("file://" + soundPath);
-                if (soundUri != null) {
-                    final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
-                    if (sfx != null) {
-                        sfx.setStreamType(AudioManager.STREAM_SYSTEM);
-                        sfx.play();
-                    }
-                }
-            }
-        }
-    }
-
-    private final void updateCallState(int state) {
-        mPhoneState = state;
-        if (false) {
-            Slog.d(TAG, "mPhoneState=" + mPhoneState
-                    + " mLowBatteryDialog=" + mLowBatteryDialog
-                    + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
-        }
-        if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
-            if (mBatteryShowLowOnEndCall) {
-                if (!mBatteryPlugged) {
-                    showLowBatteryWarning();
-                }
-                mBatteryShowLowOnEndCall = false;
-            }
-        } else {
-            if (mLowBatteryDialog != null) {
-                mLowBatteryDialog.dismiss();
-                mBatteryShowLowOnEndCall = true;
-            }
-        }
-    }
-
-    private DialogInterface.OnDismissListener mLowBatteryListener
-            = new DialogInterface.OnDismissListener() {
-        public void onDismiss(DialogInterface dialog) {
-            mLowBatteryDialog = null;
-            mBatteryLevelTextView = null;
-        }
-    };
-
-    private void scheduleCloseBatteryView() {
-        Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
-        m.arg1 = (++mBatteryViewSequence);
-        mHandler.sendMessageDelayed(m, 3000);
-    }
-
-    private void closeLastBatteryView() {
-        if (mBatteryView != null) {
-            //mBatteryView.debug();
-            WindowManagerImpl.getDefault().removeView(mBatteryView);
-            mBatteryView = null;
-        }
-    }
-
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            mSignalStrength = signalStrength;
-            updateSignalStrength();
-        }
-
-        @Override
-        public void onServiceStateChanged(ServiceState state) {
-            mServiceState = state;
-            updateSignalStrength();
-            updateCdmaRoamingIcon(state);
-            updateDataIcon();
-        }
-
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            updateCallState(state);
-            // In cdma, if a voice call is made, RSSI should switch to 1x.
-            if (isCdma()) {
-                updateSignalStrength();
-            }
-        }
-
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            mDataState = state;
-            updateDataNetType(networkType);
-            updateDataIcon();
-        }
-
-        @Override
-        public void onDataActivity(int direction) {
-            mDataActivity = direction;
-            updateDataIcon();
-        }
-    };
-
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
-        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCard.State.ABSENT;
-        }
-        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCard.State.READY;
-        }
-        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
-            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCard.State.PIN_REQUIRED;
-            }
-            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCard.State.PUK_REQUIRED;
-            }
-            else {
-                mSimState = IccCard.State.NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = IccCard.State.UNKNOWN;
-        }
-        updateDataIcon();
-    }
-
-    private boolean isCdma() {
-        return (mSignalStrength != null) && !mSignalStrength.isGsm();
-    }
-
-    private boolean isEvdo() {
-        return ( (mServiceState != null)
-                 && ((mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
-                     || (mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
-                     || (mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_B)));
-    }
-
-    private boolean hasService() {
-        if (mServiceState != null) {
-            switch (mServiceState.getState()) {
-                case ServiceState.STATE_OUT_OF_SERVICE:
-                case ServiceState.STATE_POWER_OFF:
-                    return false;
-                default:
-                    return true;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    private final void updateSignalStrength() {
-        int iconLevel = -1;
-        int[] iconList;
-
-        // Display signal strength while in "emergency calls only" mode
-        if (!hasService() && !mServiceState.isEmergencyOnly()) {
-            //Slog.d(TAG, "updateSignalStrength: no service");
-            if (Settings.System.getInt(mContext.getContentResolver(),
-                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
-                mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
-            } else {
-                mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
-            }
-            mService.updateIcon(mPhoneIcon, mPhoneData, null);
-            return;
-        }
-
-        if (!isCdma()) {
-            int asu = mSignalStrength.getGsmSignalStrength();
-
-            // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-            // asu = 0 (-113dB or less) is very weak
-            // signal, its better to show 0 bars to the user in such cases.
-            // asu = 99 is a special case, where the signal strength is unknown.
-            if (asu <= 2 || asu == 99) iconLevel = 0;
-            else if (asu >= 12) iconLevel = 4;
-            else if (asu >= 8)  iconLevel = 3;
-            else if (asu >= 5)  iconLevel = 2;
-            else iconLevel = 1;
-
-            // Though mPhone is a Manager, this call is not an IPC
-            if (mPhone.isNetworkRoaming()) {
-                iconList = sSignalImages_r;
-            } else {
-                iconList = sSignalImages;
-            }
-        } else {
-            iconList = this.sSignalImages;
-
-            // If 3G(EV) and 1x network are available than 3G should be
-            // displayed, displayed RSSI should be from the EV side.
-            // If a voice call is made then RSSI should switch to 1x.
-            if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
-                iconLevel = getEvdoLevel();
-                if (false) {
-                    Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
-                }
-            } else {
-                iconLevel = getCdmaLevel();
-            }
-        }
-        mPhoneData.iconId = iconList[iconLevel];
-        mService.updateIcon(mPhoneIcon, mPhoneData, null);
-    }
-
-    private int getCdmaLevel() {
-        final int cdmaDbm = mSignalStrength.getCdmaDbm();
-        final int cdmaEcio = mSignalStrength.getCdmaEcio();
-        int levelDbm = 0;
-        int levelEcio = 0;
-
-        if (cdmaDbm >= -75) levelDbm = 4;
-        else if (cdmaDbm >= -85) levelDbm = 3;
-        else if (cdmaDbm >= -95) levelDbm = 2;
-        else if (cdmaDbm >= -100) levelDbm = 1;
-        else levelDbm = 0;
-
-        // Ec/Io are in dB*10
-        if (cdmaEcio >= -90) levelEcio = 4;
-        else if (cdmaEcio >= -110) levelEcio = 3;
-        else if (cdmaEcio >= -130) levelEcio = 2;
-        else if (cdmaEcio >= -150) levelEcio = 1;
-        else levelEcio = 0;
-
-        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
-    }
-
-    private int getEvdoLevel() {
-        int evdoDbm = mSignalStrength.getEvdoDbm();
-        int evdoSnr = mSignalStrength.getEvdoSnr();
-        int levelEvdoDbm = 0;
-        int levelEvdoSnr = 0;
-
-        if (evdoDbm >= -65) levelEvdoDbm = 4;
-        else if (evdoDbm >= -75) levelEvdoDbm = 3;
-        else if (evdoDbm >= -90) levelEvdoDbm = 2;
-        else if (evdoDbm >= -105) levelEvdoDbm = 1;
-        else levelEvdoDbm = 0;
-
-        if (evdoSnr >= 7) levelEvdoSnr = 4;
-        else if (evdoSnr >= 5) levelEvdoSnr = 3;
-        else if (evdoSnr >= 3) levelEvdoSnr = 2;
-        else if (evdoSnr >= 1) levelEvdoSnr = 1;
-        else levelEvdoSnr = 0;
-
-        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
-    }
-
-    private final void updateDataNetType(int net) {
-        switch (net) {
-        case TelephonyManager.NETWORK_TYPE_EDGE:
-            mDataIconList = sDataNetType_e;
-            break;
-        case TelephonyManager.NETWORK_TYPE_UMTS:
-            mDataIconList = sDataNetType_3g;
-            break;
-        case TelephonyManager.NETWORK_TYPE_HSDPA:
-        case TelephonyManager.NETWORK_TYPE_HSUPA:
-        case TelephonyManager.NETWORK_TYPE_HSPA:
-            if (mHspaDataDistinguishable) {
-                mDataIconList = sDataNetType_h;
-            } else {
-                mDataIconList = sDataNetType_3g;
-            }
-            break;
-        case TelephonyManager.NETWORK_TYPE_CDMA:
-            // display 1xRTT for IS95A/B
-            mDataIconList = this.sDataNetType_1x;
-            break;
-        case TelephonyManager.NETWORK_TYPE_1xRTT:
-            mDataIconList = this.sDataNetType_1x;
-            break;
-        case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
-        case TelephonyManager.NETWORK_TYPE_EVDO_A:
-        case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            mDataIconList = sDataNetType_3g;
-            break;
-        default:
-            mDataIconList = sDataNetType_g;
-        break;
-        }
-    }
-
-    private final void updateDataIcon() {
-        int iconId;
-        boolean visible = true;
-
-        if (!isCdma()) {
-            // GSM case, we have to check also the sim state
-            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
-                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                    switch (mDataActivity) {
-                        case TelephonyManager.DATA_ACTIVITY_IN:
-                            iconId = mDataIconList[1];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_OUT:
-                            iconId = mDataIconList[2];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_INOUT:
-                            iconId = mDataIconList[3];
-                            break;
-                        default:
-                            iconId = mDataIconList[0];
-                            break;
-                    }
-                    mDataData.iconId = iconId;
-                    mService.updateIcon(mDataIcon, mDataData, null);
-                } else {
-                    visible = false;
-                }
-            } else {
-                mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
-                mService.updateIcon(mDataIcon, mDataData, null);
-            }
-        } else {
-            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
-            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                switch (mDataActivity) {
-                    case TelephonyManager.DATA_ACTIVITY_IN:
-                        iconId = mDataIconList[1];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_OUT:
-                        iconId = mDataIconList[2];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_INOUT:
-                        iconId = mDataIconList[3];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
-                    default:
-                        iconId = mDataIconList[0];
-                        break;
-                }
-                mDataData.iconId = iconId;
-                mService.updateIcon(mDataIcon, mDataData, null);
-            } else {
-                visible = false;
-            }
-        }
-
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
-        } catch (RemoteException e) {
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        if (mDataIconVisible != visible) {
-            mService.setIconVisibility(mDataIcon, visible);
-            mDataIconVisible = visible;
-        }
-    }
-
-    private final void updateVolume() {
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        final int ringerMode = audioManager.getRingerMode();
-        final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
-                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
-        final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
-                ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
-                : com.android.internal.R.drawable.stat_sys_ringer_silent;
-
-        if (visible) {
-            mVolumeData.iconId = iconId;
-            mService.updateIcon(mVolumeIcon, mVolumeData, null);
-        }
-        if (visible != mVolumeVisible) {
-            mService.setIconVisibility(mVolumeIcon, visible);
-            mVolumeVisible = visible;
-        }
-    }
-
-    private final void updateBluetooth(Intent intent) {
-        int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
-        String action = intent.getAction();
-        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
-            mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
-        } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
-            mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
-                    BluetoothHeadset.STATE_ERROR);
-        } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
-            BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
-            if (a2dp.getConnectedSinks().size() != 0) {
-                mBluetoothA2dpConnected = true;
-            } else {
-                mBluetoothA2dpConnected = false;
-            }
-        } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
-            mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
-                    BluetoothPbap.STATE_DISCONNECTED);
-        } else {
-            return;
-        }
-
-        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
-                mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
-            iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
-        }
-
-        mBluetoothData.iconId = iconId;
-        mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
-        mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
-    }
-
-    private final void updateWifi(Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-
-            final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
-            if (!enabled) {
-                // If disabled, hide the icon. (We show icon when connected.)
-                mService.setIconVisibility(mWifiIcon, false);
-            }
-
-        } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
-            final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
-                                                           false);
-            if (!enabled) {
-                mService.setIconVisibility(mWifiIcon, 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];
-                }
-
-                // Show the icon since wi-fi is connected
-                mService.setIconVisibility(mWifiIcon, true);
-
-            } else {
-                mLastWifiSignalLevel = -1;
-                mIsWifiConnected = false;
-                iconId = sWifiSignalImages[0];
-
-                // Hide the icon since we're not connected
-                mService.setIconVisibility(mWifiIcon, false);
-            }
-
-            mWifiData.iconId = iconId;
-            mService.updateIcon(mWifiIcon, mWifiData, null);
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
-                                                                  sWifiSignalImages.length);
-            if (newSignalLevel != mLastWifiSignalLevel) {
-                mLastWifiSignalLevel = newSignalLevel;
-                if (mIsWifiConnected) {
-                    mWifiData.iconId = sWifiSignalImages[newSignalLevel];
-                } else {
-                    mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
-                }
-                mService.updateIcon(mWifiIcon, mWifiData, null);
-            }
-        }
-    }
-
-    private final void updateGps(Intent intent) {
-        final String action = intent.getAction();
-        final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
-
-        if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
-            // GPS is getting fixes
-            mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
-            mService.setIconVisibility(mGpsIcon, true);
-        } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
-            // GPS is off
-            mService.setIconVisibility(mGpsIcon, false);
-        } else {
-            // GPS is on, but not receiving fixes
-            mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
-            mService.setIconVisibility(mGpsIcon, true);
-        }
-    }
-
-    private final void updateTTY(Intent intent) {
-        final String action = intent.getAction();
-        final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
-
-        if (false) Slog.v(TAG, "updateTTY: enabled: " + enabled);
-
-        if (enabled) {
-            // TTY is on
-            if (false) Slog.v(TAG, "updateTTY: set TTY on");
-            mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
-            mService.setIconVisibility(mTTYModeIcon, true);
-        } else {
-            // TTY is off
-            if (false) Slog.v(TAG, "updateTTY: set TTY off");
-            mService.setIconVisibility(mTTYModeIcon, false);
-        }
-    }
-
-    private final void updateCdmaRoamingIcon(ServiceState state) {
-        if (!hasService()) {
-            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-            return;
-        }
-
-        if (!isCdma()) {
-            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-            return;
-        }
-
-        int[] iconList = sRoamingIndicatorImages_cdma;
-        int iconIndex = state.getCdmaEriIconIndex();
-        int iconMode = state.getCdmaEriIconMode();
-
-        if (iconIndex == -1) {
-            Slog.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
-            return;
-        }
-
-        if (iconMode == -1) {
-            Slog.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
-            return;
-        }
-
-        if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
-            if (false) Slog.v(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
-            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-            return;
-        }
-
-        switch (iconMode) {
-            case EriInfo.ROAMING_ICON_MODE_NORMAL:
-                mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
-                mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
-                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
-                break;
-            case EriInfo.ROAMING_ICON_MODE_FLASH:
-                mCdmaRoamingIndicatorIconData.iconId =
-                        com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
-                mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
-                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
-                break;
-
-        }
-        mService.updateIcon(mPhoneIcon, mPhoneData, null);
-    }
-
-
-    private class StatusBarHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case EVENT_BATTERY_CLOSE:
-                if (msg.arg1 == mBatteryViewSequence) {
-                    closeLastBatteryView();
-                }
-                break;
-            }
-        }
-    }
-}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
deleted file mode 100644
index 93c8d34..0000000
--- a/services/java/com/android/server/status/StatusBarService.java
+++ /dev/null
@@ -1,1881 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import com.android.internal.R;
-import com.android.internal.util.CharSequences;
-
-import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.IStatusBar;
-import android.app.PendingIntent;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Telephony;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.widget.FrameLayout;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
-
-
-/**
- * The public (ok, semi-public) service for the status bar.
- * <p>
- * This interesting thing to note about this class is that most of the methods that
- * are called from other classes just post a message, and everything else is batched
- * and coalesced into a series of calls to methods that all start with "perform."
- * There are two reasons for this.  The first is that some of the methods (activate/deactivate)
- * are on IStatusBar, so they're called from the thread pool and they need to make their
- * way onto the UI thread.  The second is that the message queue is stopped while animations
- * are happening in order to make for smoother transitions.
- * <p>
- * Each icon is either an icon or an icon and a notification.  They're treated mostly
- * separately throughout the code, although they both use the same key, which is assigned
- * when they are created.
- */
-public class StatusBarService extends IStatusBar.Stub
-{
-    static final String TAG = "StatusBar";
-    static final boolean SPEW = false;
-
-    static final int EXPANDED_LEAVE_ALONE = -10000;
-    static final int EXPANDED_FULL_OPEN = -10001;
-
-    private static final int MSG_ANIMATE = 1000;
-    private static final int MSG_ANIMATE_REVEAL = 1001;
-
-    private static final int OP_ADD_ICON = 1;
-    private static final int OP_UPDATE_ICON = 2;
-    private static final int OP_REMOVE_ICON = 3;
-    private static final int OP_SET_VISIBLE = 4;
-    private static final int OP_EXPAND = 5;
-    private static final int OP_TOGGLE = 6;
-    private static final int OP_DISABLE = 7;
-    private class PendingOp {
-        IBinder key;
-        int code;
-        IconData iconData;
-        NotificationData notificationData;
-        boolean visible;
-        int integer;
-    }
-
-    private class DisableRecord implements IBinder.DeathRecipient {
-        String pkg;
-        int what;
-        IBinder token;
-
-        public void binderDied() {
-            Slog.i(TAG, "binder died for pkg=" + pkg);
-            disable(0, token, pkg);
-            token.unlinkToDeath(this, 0);
-        }
-    }
-
-    public interface NotificationCallbacks {
-        void onSetDisabled(int status);
-        void onClearAll();
-        void onNotificationClick(String pkg, String tag, int id);
-        void onPanelRevealed();
-    }
-
-    private class ExpandedDialog extends Dialog {
-        ExpandedDialog(Context context) {
-            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-            switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_BACK:
-                if (!down) {
-                    StatusBarService.this.deactivate();
-                }
-                return true;
-            }
-            return super.dispatchKeyEvent(event);
-        }
-    }
-    
-    final Context mContext;
-    final Display mDisplay;
-    StatusBarView mStatusBarView;
-    int mPixelFormat;
-    H mHandler = new H();
-    Object mQueueLock = new Object();
-    ArrayList<PendingOp> mQueue = new ArrayList<PendingOp>();
-    NotificationCallbacks mNotificationCallbacks;
-    
-    // All accesses to mIconMap and mNotificationData are syncronized on those objects,
-    // but this is only so dump() can work correctly.  Modifying these outside of the UI
-    // thread will not work, there are places in the code that unlock and reaquire between
-    // reads and require them to not be modified.
-
-    // icons
-    HashMap<IBinder,StatusBarIcon> mIconMap = new HashMap<IBinder,StatusBarIcon>();
-    ArrayList<StatusBarIcon> mIconList = new ArrayList<StatusBarIcon>();
-    String[] mRightIconSlots;
-    StatusBarIcon[] mRightIcons;
-    LinearLayout mIcons;
-    IconMerger mNotificationIcons;
-    LinearLayout mStatusIcons;
-    StatusBarIcon mMoreIcon;
-    private UninstallReceiver mUninstallReceiver;
-
-    // expanded notifications
-    NotificationViewList mNotificationData = new NotificationViewList();
-    Dialog mExpandedDialog;
-    ExpandedView mExpandedView;
-    WindowManager.LayoutParams mExpandedParams;
-    ScrollView mScrollView;
-    View mNotificationLinearLayout;
-    TextView mOngoingTitle;
-    LinearLayout mOngoingItems;
-    TextView mLatestTitle;
-    LinearLayout mLatestItems;
-    TextView mNoNotificationsTitle;
-    TextView mSpnLabel;
-    TextView mPlmnLabel;
-    TextView mClearButton;
-    View mExpandedContents;
-    CloseDragHandle mCloseView;
-    int[] mPositionTmp = new int[2];
-    boolean mExpanded;
-    boolean mExpandedVisible;
-
-    // the date view
-    DateView mDateView;
-
-    // the tracker view
-    TrackingView mTrackingView;
-    WindowManager.LayoutParams mTrackingParams;
-    int mTrackingPosition; // the position of the top of the tracking view.
-
-    // ticker
-    private Ticker mTicker;
-    private View mTickerView;
-    private boolean mTicking;
-    
-    // Tracking finger for opening/closing.
-    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
-    boolean mTracking;
-    VelocityTracker mVelocityTracker;
-    
-    static final int ANIM_FRAME_DURATION = (1000/60);
-    
-    boolean mAnimating;
-    long mCurAnimationTime;
-    float mDisplayHeight;
-    float mAnimY;
-    float mAnimVel;
-    float mAnimAccel;
-    long mAnimLastTime;
-    boolean mAnimatingReveal = false;
-    int mViewDelta;
-    int[] mAbsPos = new int[2];
-    
-    // for disabling the status bar
-    ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
-    int mDisabled = 0;
-
-    /**
-     * Construct the service, add the status bar view to the window manager
-     */
-    public StatusBarService(Context context) {
-        mContext = context;
-        mDisplay = ((WindowManager)context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
-        makeStatusBarView(context);
-        mUninstallReceiver = new UninstallReceiver();
-    }
-
-    public void setNotificationCallbacks(NotificationCallbacks listener) {
-        mNotificationCallbacks = listener;
-    }
-
-    // ================================================================================
-    // Constructing the view
-    // ================================================================================
-    private void makeStatusBarView(Context context) {
-        Resources res = context.getResources();
-        mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);
-        mRightIcons = new StatusBarIcon[mRightIconSlots.length];
-
-        ExpandedView expanded = (ExpandedView)View.inflate(context,
-                com.android.internal.R.layout.status_bar_expanded, null);
-        expanded.mService = this;
-        StatusBarView sb = (StatusBarView)View.inflate(context,
-                com.android.internal.R.layout.status_bar, null);
-        sb.mService = this;
-
-        // figure out which pixel-format to use for the status bar.
-        mPixelFormat = PixelFormat.TRANSLUCENT;
-        Drawable bg = sb.getBackground();
-        if (bg != null) {
-            mPixelFormat = bg.getOpacity();
-        }
-
-        mStatusBarView = sb;
-        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
-        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
-        mNotificationIcons.service = this;
-        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
-        mTickerView = sb.findViewById(R.id.ticker);
-        mDateView = (DateView)sb.findViewById(R.id.date);
-
-        mExpandedDialog = new ExpandedDialog(context);
-        mExpandedView = expanded;
-        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
-        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
-        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
-        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
-        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
-        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
-        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-        mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel);
-        mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel);
-        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
-        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
-        mOngoingTitle.setVisibility(View.GONE);
-        mLatestTitle.setVisibility(View.GONE);
-        
-        mTicker = new MyTicker(context, sb);
-
-        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
-        tickerView.mTicker = mTicker;
-
-        mTrackingView = (TrackingView)View.inflate(context,
-                com.android.internal.R.layout.status_bar_tracking, null);
-        mTrackingView.mService = this;
-        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
-        mCloseView.mService = this;
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        // add the more icon for the notifications
-        IconData moreData = IconData.makeIcon(null, context.getPackageName(),
-                R.drawable.stat_notify_more, 0, 42);
-        mMoreIcon = new StatusBarIcon(context, moreData, mNotificationIcons);
-        mMoreIcon.view.setId(R.drawable.stat_notify_more);
-        mNotificationIcons.moreIcon = mMoreIcon;
-        mNotificationIcons.addView(mMoreIcon.view);
-
-        // set the inital view visibility
-        setAreThereNotifications();
-        mDateView.setVisibility(View.INVISIBLE);
-
-        // before we register for broadcasts
-        mPlmnLabel.setText(R.string.lockscreen_carrier_default);
-        mPlmnLabel.setVisibility(View.VISIBLE);
-        mSpnLabel.setText("");
-        mSpnLabel.setVisibility(View.GONE);
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
-        context.registerReceiver(mBroadcastReceiver, filter);
-    }
-
-    public void systemReady() {
-        final StatusBarView view = mStatusBarView;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                view.getContext().getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.status_bar_height),
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
-                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
-                mPixelFormat);
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBar");
-        lp.windowAnimations = R.style.Animation_StatusBar;
-
-        WindowManagerImpl.getDefault().addView(view, lp);
-    }
-    
-    // ================================================================================
-    // From IStatusBar
-    // ================================================================================
-    public void activate() {
-        enforceExpandStatusBar();
-        addPendingOp(OP_EXPAND, null, true);
-    }
-
-    public void deactivate() {
-        enforceExpandStatusBar();
-        addPendingOp(OP_EXPAND, null, false);
-    }
-
-    public void toggle() {
-        enforceExpandStatusBar();
-        addPendingOp(OP_TOGGLE, null, false);
-    }
-
-    public void disable(int what, IBinder token, String pkg) {
-        enforceStatusBar();
-        synchronized (mNotificationCallbacks) {
-            // This is a little gross, but I think it's safe as long as nobody else
-            // synchronizes on mNotificationCallbacks.  It's important that the the callback
-            // and the pending op get done in the correct order and not interleaved with
-            // other calls, otherwise they'll get out of sync.
-            int net;
-            synchronized (mDisableRecords) {
-                manageDisableListLocked(what, token, pkg);
-                net = gatherDisableActionsLocked();
-                mNotificationCallbacks.onSetDisabled(net);
-            }
-            addPendingOp(OP_DISABLE, net);
-        }
-    }
-
-    public IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel) {
-        enforceStatusBar();
-        return addIcon(IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null);
-    }
-
-    public void updateIcon(IBinder key,
-            String slot, String iconPackage, int iconId, int iconLevel) {
-        enforceStatusBar();
-        updateIcon(key, IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null);
-    }
-
-    public void removeIcon(IBinder key) {
-        enforceStatusBar();
-        addPendingOp(OP_REMOVE_ICON, key, null, null, -1);
-    }
-
-    private void enforceStatusBar() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.STATUS_BAR,
-                "StatusBarService");
-    }
-
-    private void enforceExpandStatusBar() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.EXPAND_STATUS_BAR,
-                "StatusBarService");
-    }
-
-    // ================================================================================
-    // Can be called from any thread
-    // ================================================================================
-    public IBinder addIcon(IconData data, NotificationData n) {
-        int slot;
-        // assert early-on if they using a slot that doesn't exist.
-        if (data != null && n == null) {
-            slot = getRightIconIndex(data.slot);
-            if (slot < 0) {
-                throw new SecurityException("invalid status bar icon slot: "
-                        + (data.slot != null ? "'" + data.slot + "'" : "null"));
-            }
-        } else {
-            slot = -1;
-        }
-        IBinder key = new Binder();
-        addPendingOp(OP_ADD_ICON, key, data, n, -1);
-        return key;
-    }
-
-    public void updateIcon(IBinder key, IconData data, NotificationData n) {
-        addPendingOp(OP_UPDATE_ICON, key, data, n, -1);
-    }
-
-    public void setIconVisibility(IBinder key, boolean visible) {
-        addPendingOp(OP_SET_VISIBLE, key, visible);
-    }
-
-    private void addPendingOp(int code, IBinder key, IconData data, NotificationData n, int i) {
-        synchronized (mQueueLock) {
-            PendingOp op = new PendingOp();
-            op.key = key;
-            op.code = code;
-            op.iconData = data == null ? null : data.clone();
-            op.notificationData = n;
-            op.integer = i;
-            mQueue.add(op);
-            if (mQueue.size() == 1) {
-                mHandler.sendEmptyMessage(2);
-            }
-        }
-    }
-
-    private void addPendingOp(int code, IBinder key, boolean visible) {
-        synchronized (mQueueLock) {
-            PendingOp op = new PendingOp();
-            op.key = key;
-            op.code = code;
-            op.visible = visible;
-            mQueue.add(op);
-            if (mQueue.size() == 1) {
-                mHandler.sendEmptyMessage(1);
-            }
-        }
-    }
-
-    private void addPendingOp(int code, int integer) {
-        synchronized (mQueueLock) {
-            PendingOp op = new PendingOp();
-            op.code = code;
-            op.integer = integer;
-            mQueue.add(op);
-            if (mQueue.size() == 1) {
-                mHandler.sendEmptyMessage(1);
-            }
-        }
-    }
-
-    // lock on mDisableRecords
-    void manageDisableListLocked(int what, IBinder token, String pkg) {
-        if (SPEW) {
-            Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what)
-                    + " pkg=" + pkg);
-        }
-        // update the list
-        synchronized (mDisableRecords) {
-            final int N = mDisableRecords.size();
-            DisableRecord tok = null;
-            int i;
-            for (i=0; i<N; i++) {
-                DisableRecord t = mDisableRecords.get(i);
-                if (t.token == token) {
-                    tok = t;
-                    break;
-                }
-            }
-            if (what == 0 || !token.isBinderAlive()) {
-                if (tok != null) {
-                    mDisableRecords.remove(i);
-                    tok.token.unlinkToDeath(tok, 0);
-                }
-            } else {
-                if (tok == null) {
-                    tok = new DisableRecord();
-                    try {
-                        token.linkToDeath(tok, 0);
-                    }
-                    catch (RemoteException ex) {
-                        return; // give up
-                    }
-                    mDisableRecords.add(tok);
-                }
-                tok.what = what;
-                tok.token = token;
-                tok.pkg = pkg;
-            }
-        }
-    }
-
-    // lock on mDisableRecords
-    int gatherDisableActionsLocked() {
-        final int N = mDisableRecords.size();
-        // gather the new net flags
-        int net = 0;
-        for (int i=0; i<N; i++) {
-            net |= mDisableRecords.get(i).what;
-        }
-        return net;
-    }
-
-    private int getRightIconIndex(String slot) {
-        final int N = mRightIconSlots.length;
-        for (int i=0; i<N; i++) {
-            if (mRightIconSlots[i].equals(slot)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    // ================================================================================
-    // Always called from UI thread
-    // ================================================================================
-    /**
-     * All changes to the status bar and notifications funnel through here and are batched.
-     */
-    private class H extends Handler {
-        public void handleMessage(Message m) {
-            if (m.what == MSG_ANIMATE) {
-                doAnimation();
-                return;
-            }
-            if (m.what == MSG_ANIMATE_REVEAL) {
-                doRevealAnimation();
-                return;
-            }
-
-            ArrayList<PendingOp> queue;
-            synchronized (mQueueLock) {
-                queue = mQueue;
-                mQueue = new ArrayList<PendingOp>();
-            }
-
-            boolean wasExpanded = mExpanded;
-
-            // for each one in the queue, find all of the ones with the same key
-            // and collapse that down into a final op and/or call to setVisibility, etc
-            boolean expand = wasExpanded;
-            boolean doExpand = false;
-            boolean doDisable = false;
-            int disableWhat = 0;
-            int N = queue.size();
-            while (N > 0) {
-                PendingOp op = queue.get(0);
-                boolean doOp = false;
-                boolean visible = false;
-                boolean doVisibility = false;
-                if (op.code == OP_SET_VISIBLE) {
-                    doVisibility = true;
-                    visible = op.visible;
-                }
-                else if (op.code == OP_EXPAND) {
-                    doExpand = true;
-                    expand = op.visible;
-                }
-                else if (op.code == OP_TOGGLE) {
-                    doExpand = true;
-                    expand = !expand;
-                }
-                else {
-                    doOp = true;
-                }
-
-                if (alwaysHandle(op.code)) {
-                    // coalesce these
-                    for (int i=1; i<N; i++) {
-                        PendingOp o = queue.get(i);
-                        if (!alwaysHandle(o.code) && o.key == op.key) {
-                            if (o.code == OP_SET_VISIBLE) {
-                                visible = o.visible;
-                                doVisibility = true;
-                            }
-                            else if (o.code == OP_EXPAND) {
-                                expand = o.visible;
-                                doExpand = true;
-                            }
-                            else {
-                                op.code = o.code;
-                                op.iconData = o.iconData;
-                                op.notificationData = o.notificationData;
-                            }
-                            queue.remove(i);
-                            i--;
-                            N--;
-                        }
-                    }
-                }
-
-                queue.remove(0);
-                N--;
-
-                if (doOp) {
-                    switch (op.code) {
-                        case OP_ADD_ICON:
-                        case OP_UPDATE_ICON:
-                            performAddUpdateIcon(op.key, op.iconData, op.notificationData);
-                            break;
-                        case OP_REMOVE_ICON:
-                            performRemoveIcon(op.key);
-                            break;
-                        case OP_DISABLE:
-                            doDisable = true;
-                            disableWhat = op.integer;
-                            break;
-                    }
-                }
-                if (doVisibility && op.code != OP_REMOVE_ICON) {
-                    performSetIconVisibility(op.key, visible);
-                }
-            }
-
-            if (queue.size() != 0) {
-                throw new RuntimeException("Assertion failed: queue.size=" + queue.size());
-            }
-            if (doExpand) {
-                // this is last so that we capture all of the pending changes before doing it
-                if (expand) {
-                    animateExpand();
-                } else {
-                    animateCollapse();
-                }
-            }
-            if (doDisable) {
-                performDisableActions(disableWhat);
-            }
-        }
-    }
-
-    private boolean alwaysHandle(int code) {
-        return code == OP_DISABLE;
-    }
-
-    /* private */ void performAddUpdateIcon(IBinder key, IconData data, NotificationData n)
-                        throws StatusBarException {
-        if (SPEW) {
-            Slog.d(TAG, "performAddUpdateIcon icon=" + data + " notification=" + n + " key=" + key);
-        }
-        // notification
-        if (n != null) {
-            StatusBarNotification notification = getNotification(key);
-            NotificationData oldData = null;
-            if (notification == null) {
-                // add
-                notification = new StatusBarNotification();
-                notification.key = key;
-                notification.data = n;
-                synchronized (mNotificationData) {
-                    mNotificationData.add(notification);
-                }
-                addNotificationView(notification);
-                setAreThereNotifications();
-            } else {
-                // update
-                oldData = notification.data;
-                notification.data = n;
-                updateNotificationView(notification, oldData);
-            }
-            // Show the ticker if one is requested, and the text is different
-            // than the currently displayed ticker.  Also don't do this
-            // until status bar window is attached to the window manager,
-            // because...  well, what's the point otherwise?  And trying to
-            // run a ticker without being attached will crash!
-            if (n.tickerText != null && mStatusBarView.getWindowToken() != null
-                    && (oldData == null
-                        || oldData.tickerText == null
-                        || !CharSequences.equals(oldData.tickerText, n.tickerText))) {
-                if (0 == (mDisabled & 
-                    (StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
-                    mTicker.addEntry(n, StatusBarIcon.getIcon(mContext, data), n.tickerText);
-                }
-            }
-            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        }
-
-        // icon
-        synchronized (mIconMap) {
-            StatusBarIcon icon = mIconMap.get(key);
-            if (icon == null) {
-                // add
-                LinearLayout v = n == null ? mStatusIcons : mNotificationIcons;
-
-                icon = new StatusBarIcon(mContext, data, v);
-                mIconMap.put(key, icon);
-                mIconList.add(icon);
-
-                if (n == null) {
-                    int slotIndex = getRightIconIndex(data.slot);
-                    StatusBarIcon[] rightIcons = mRightIcons;
-                    if (rightIcons[slotIndex] == null) {
-                        int pos = 0;
-                        for (int i=mRightIcons.length-1; i>slotIndex; i--) {
-                            StatusBarIcon ic = rightIcons[i];
-                            if (ic != null) {
-                                pos++;
-                            }
-                        }
-                        rightIcons[slotIndex] = icon;
-                        mStatusIcons.addView(icon.view, pos);
-                    } else {
-                        Slog.e(TAG, "duplicate icon in slot " + slotIndex + "/" + data.slot);
-                        mIconMap.remove(key);
-                        mIconList.remove(icon);
-                        return ;
-                    }
-                } else {
-                    int iconIndex = mNotificationData.getIconIndex(n);
-                    mNotificationIcons.addView(icon.view, iconIndex);
-                }
-            } else {
-                if (n == null) {
-                    // right hand side icons -- these don't reorder
-                    icon.update(mContext, data);
-                } else {
-                    // remove old
-                    ViewGroup parent = (ViewGroup)icon.view.getParent();
-                    parent.removeView(icon.view);
-                    // add new
-                    icon.update(mContext, data);
-                    int iconIndex = mNotificationData.getIconIndex(n);
-                    mNotificationIcons.addView(icon.view, iconIndex);
-                }
-            }
-        }
-    }
-
-    /* private */ void performSetIconVisibility(IBinder key, boolean visible) {
-        synchronized (mIconMap) {
-            if (SPEW) {
-                Slog.d(TAG, "performSetIconVisibility key=" + key + " visible=" + visible);
-            }
-            StatusBarIcon icon = mIconMap.get(key);
-            icon.view.setVisibility(visible ? View.VISIBLE : View.GONE);
-        }
-    }
-    
-    /* private */ void performRemoveIcon(IBinder key) {
-        synchronized (this) {
-            if (SPEW) {
-                Slog.d(TAG, "performRemoveIcon key=" + key);
-            }
-            StatusBarIcon icon = mIconMap.remove(key);
-            mIconList.remove(icon);
-            if (icon != null) {
-                ViewGroup parent = (ViewGroup)icon.view.getParent();
-                parent.removeView(icon.view);
-                int slotIndex = getRightIconIndex(icon.mData.slot);
-                if (slotIndex >= 0) {
-                    mRightIcons[slotIndex] = null;
-                }
-            }
-            StatusBarNotification notification = getNotification(key);
-            if (notification != null) {
-                removeNotificationView(notification);
-                synchronized (mNotificationData) {
-                    mNotificationData.remove(notification);
-                }
-                setAreThereNotifications();
-            }
-        }
-    }
-
-    int getIconNumberForView(View v) {
-        synchronized (mIconMap) {
-            StatusBarIcon icon = null;
-            final int N = mIconList.size();
-            for (int i=0; i<N; i++) {
-                StatusBarIcon ic = mIconList.get(i);
-                if (ic.view == v) {
-                    icon = ic;
-                    break;
-                }
-            }
-            if (icon != null) {
-                return icon.getNumber();
-            } else {
-                return -1;
-            }
-        }
-    }
-
-
-    StatusBarNotification getNotification(IBinder key) {
-        synchronized (mNotificationData) {
-            return mNotificationData.get(key);
-        }
-    }
-
-    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
-        public void onFocusChange(View v, boolean hasFocus) {
-            // Because 'v' is a ViewGroup, all its children will be (un)selected
-            // too, which allows marqueeing to work.
-            v.setSelected(hasFocus);
-        }
-    };
-    
-    View makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
-        NotificationData n = notification.data;
-        RemoteViews remoteViews = n.contentView;
-        if (remoteViews == null) {
-            return null;
-        }
-
-        // create the row view
-        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event, parent, false);
-
-        // bind the click event to the content area
-        ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content);
-        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        content.setOnFocusChangeListener(mFocusChangeListener);
-        PendingIntent contentIntent = n.contentIntent;
-        if (contentIntent != null) {
-            content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.tag, n.id));
-        }
-
-        View child = null;
-        Exception exception = null;
-        try {
-            child = remoteViews.apply(mContext, content);
-        }
-        catch (RuntimeException e) {
-            exception = e;
-        }
-        if (child == null) {
-            Slog.e(TAG, "couldn't inflate view for package " + n.pkg, exception);
-            return null;
-        }
-        content.addView(child);
-
-        row.setDrawingCacheEnabled(true);
-
-        notification.view = row;
-        notification.contentView = child;
-
-        return row;
-    }
-
-    void addNotificationView(StatusBarNotification notification) {
-        if (notification.view != null) {
-            throw new RuntimeException("Assertion failed: notification.view="
-                    + notification.view);
-        }
-
-        LinearLayout parent = notification.data.ongoingEvent ? mOngoingItems : mLatestItems;
-
-        View child = makeNotificationView(notification, parent);
-        if (child == null) {
-            return ;
-        }
-
-        int index = mNotificationData.getExpandedIndex(notification);
-        parent.addView(child, index);
-    }
-
-    /**
-     * Remove the old one and put the new one in its place.
-     * @param notification the notification
-     */
-    void updateNotificationView(StatusBarNotification notification, NotificationData oldData) {
-        NotificationData n = notification.data;
-        if (oldData != null && n != null
-                && n.when == oldData.when
-                && n.ongoingEvent == oldData.ongoingEvent
-                && n.contentView != null && oldData.contentView != null
-                && n.contentView.getPackage() != null
-                && oldData.contentView.getPackage() != null
-                && oldData.contentView.getPackage().equals(n.contentView.getPackage())
-                && oldData.contentView.getLayoutId() == n.contentView.getLayoutId()
-                && notification.view != null) {
-            mNotificationData.update(notification);
-            try {
-                n.contentView.reapply(mContext, notification.contentView);
-
-                // update the contentIntent
-                ViewGroup content = (ViewGroup)notification.view.findViewById(
-                        com.android.internal.R.id.content);
-                PendingIntent contentIntent = n.contentIntent;
-                if (contentIntent != null) {
-                    content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.tag, n.id));
-                }
-            }
-            catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "couldn't reapply views for package " + n.contentView.getPackage(), e);
-                removeNotificationView(notification);
-            }
-        } else {
-            mNotificationData.update(notification);
-            removeNotificationView(notification);
-            addNotificationView(notification);
-        }
-        setAreThereNotifications();
-    }
-
-    void removeNotificationView(StatusBarNotification notification) {
-        View v = notification.view;
-        if (v != null) {
-            ViewGroup parent = (ViewGroup)v.getParent();
-            parent.removeView(v);
-            notification.view = null;
-        }
-    }
-
-    private void setAreThereNotifications() {
-        boolean ongoing = mOngoingItems.getChildCount() != 0;
-        boolean latest = mLatestItems.getChildCount() != 0;
-
-        if (mNotificationData.hasClearableItems()) {
-            mClearButton.setVisibility(View.VISIBLE);
-        } else {
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-
-        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
-        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
-
-        if (ongoing || latest) {
-            mNoNotificationsTitle.setVisibility(View.GONE);
-        } else {
-            mNoNotificationsTitle.setVisibility(View.VISIBLE);
-        }
-    }
-
-    private void makeExpandedVisible() {
-        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = true;
-        panelSlightlyVisible(true);
-        
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mExpandedView.requestFocus(View.FOCUS_FORWARD);
-        mTrackingView.setVisibility(View.VISIBLE);
-        
-        if (!mTicking) {
-            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-    }
-    
-    void animateExpand() {
-        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        prepareTracking(0, true);
-        performFling(0, 2000.0f, true);
-    }
-    
-    void animateCollapse() {
-        if (SPEW) {
-            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
-                    + " mExpandedVisible=" + mExpandedVisible
-                    + " mExpanded=" + mExpanded
-                    + " mAnimating=" + mAnimating
-                    + " mAnimY=" + mAnimY
-                    + " mAnimVel=" + mAnimVel);
-        }
-        
-        if (!mExpandedVisible) {
-            return;
-        }
-
-        int y;
-        if (mAnimating) {
-            y = (int)mAnimY;
-        } else {
-            y = mDisplay.getHeight()-1;
-        }
-        // Let the fling think that we're open so it goes in the right direction
-        // and doesn't try to re-open the windowshade.
-        mExpanded = true;
-        prepareTracking(y, false);
-        performFling(y, -2000.0f, true);
-    }
-    
-    void performExpand() {
-        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        // It seems strange to sometimes not expand...
-        if (false) {
-            synchronized (mNotificationData) {
-                if (mNotificationData.size() == 0) {
-                    return;
-                }
-            }
-        }
-        
-        mExpanded = true;
-        makeExpandedVisible();
-        updateExpandedViewPos(EXPANDED_FULL_OPEN);
-
-        if (false) postStartTracing();
-    }
-
-    void performCollapse() {
-        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
-                + " mExpandedVisible=" + mExpandedVisible);
-        
-        if (!mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = false;
-        panelSlightlyVisible(false);
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mTrackingView.setVisibility(View.GONE);
-
-        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
-            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
-        
-        if (!mExpanded) {
-            return;
-        }
-        mExpanded = false;
-    }
-
-    void doAnimation() {
-        if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation");
-            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
-            incrementAnim();
-            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            if (mAnimY >= mDisplay.getHeight()-1) {
-                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
-                mAnimating = false;
-                updateExpandedViewPos(EXPANDED_FULL_OPEN);
-                performExpand();
-            }
-            else if (mAnimY < mStatusBarView.getHeight()) {
-                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
-                mAnimating = false;
-                updateExpandedViewPos(0);
-                performCollapse();
-            }
-            else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-            }
-        }
-    }
-
-    void stopTracking() {
-        mTracking = false;
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-    }
-
-    void incrementAnim() {
-        long now = SystemClock.uptimeMillis();
-        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
-        final float y = mAnimY;
-        final float v = mAnimVel;                                   // px/s
-        final float a = mAnimAccel;                                 // px/s/s
-        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
-        mAnimVel = v + (a*t);                                       // px/s
-        mAnimLastTime = now;                                        // ms
-        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
-        //        + " mAnimAccel=" + mAnimAccel);
-    }
-
-    void doRevealAnimation() {
-        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
-        if (mAnimatingReveal && mAnimating && mAnimY < h) {
-            incrementAnim();
-            if (mAnimY >= h) {
-                mAnimY = h;
-                updateExpandedViewPos((int)mAnimY);
-            } else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                        mCurAnimationTime);
-            }
-        }
-    }
-    
-    void prepareTracking(int y, boolean opening) {
-        mTracking = true;
-        mVelocityTracker = VelocityTracker.obtain();
-        if (opening) {
-            mAnimAccel = 2000.0f;
-            mAnimVel = 200;
-            mAnimY = mStatusBarView.getHeight();
-            updateExpandedViewPos((int)mAnimY);
-            mAnimating = true;
-            mAnimatingReveal = true;
-            mHandler.removeMessages(MSG_ANIMATE);
-            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-            long now = SystemClock.uptimeMillis();
-            mAnimLastTime = now;
-            mCurAnimationTime = now + ANIM_FRAME_DURATION;
-            mAnimating = true;
-            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                    mCurAnimationTime);
-            makeExpandedVisible();
-        } else {
-            // it's open, close it?
-            if (mAnimating) {
-                mAnimating = false;
-                mHandler.removeMessages(MSG_ANIMATE);
-            }
-            updateExpandedViewPos(y + mViewDelta);
-        }
-    }
-    
-    void performFling(int y, float vel, boolean always) {
-        mAnimatingReveal = false;
-        mDisplayHeight = mDisplay.getHeight();
-
-        mAnimY = y;
-        mAnimVel = vel;
-
-        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
-        if (mExpanded) {
-            if (!always && (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
-                // We are expanded, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the expanded position.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are expanded and are now going to animate away.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        } else {
-            if (always || (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
-                // We are collapsed, and they moved enough to allow us to
-                // expand.  Animate in the notifications.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are collapsed, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the collapsed position.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        }
-        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
-        //        + " mAnimAccel=" + mAnimAccel);
-
-        long now = SystemClock.uptimeMillis();
-        mAnimLastTime = now;
-        mCurAnimationTime = now + ANIM_FRAME_DURATION;
-        mAnimating = true;
-        mHandler.removeMessages(MSG_ANIMATE);
-        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-        stopTracking();
-    }
-    
-    boolean interceptTouchEvent(MotionEvent event) {
-        if (SPEW) {
-            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
-                + mDisabled);
-        }
-
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return false;
-        }
-        
-        final int statusBarSize = mStatusBarView.getHeight();
-        final int hitSize = statusBarSize*2;
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final int y = (int)event.getRawY();
-
-            if (!mExpanded) {
-                mViewDelta = statusBarSize - y;
-            } else {
-                mTrackingView.getLocationOnScreen(mAbsPos);
-                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
-            }
-            if ((!mExpanded && y < hitSize) ||
-                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
-
-                // We drop events at the edge of the screen to make the windowshade come
-                // down by accident less, especially when pushing open a device with a keyboard
-                // that rotates (like g1 and droid)
-                int x = (int)event.getRawX();
-                final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
-                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    mVelocityTracker.addMovement(event);
-                }
-            }
-        } else if (mTracking) {
-            mVelocityTracker.addMovement(event);
-            final int minY = statusBarSize + mCloseView.getHeight();
-            if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                int y = (int)event.getRawY();
-                if (mAnimatingReveal && y < minY) {
-                    // nothing
-                } else  {
-                    mAnimatingReveal = false;
-                    updateExpandedViewPos(y + mViewDelta);
-                }
-            } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                mVelocityTracker.computeCurrentVelocity(1000);
-
-                float yVel = mVelocityTracker.getYVelocity();
-                boolean negative = yVel < 0;
-
-                float xVel = mVelocityTracker.getXVelocity();
-                if (xVel < 0) {
-                    xVel = -xVel;
-                }
-                if (xVel > 150.0f) {
-                    xVel = 150.0f; // limit how much we care about the x axis
-                }
-
-                float vel = (float)Math.hypot(yVel, xVel);
-                if (negative) {
-                    vel = -vel;
-                }
-                
-                performFling((int)event.getRawY(), vel, false);
-            }
-            
-        }
-        return false;
-    }
-
-    private class Launcher implements View.OnClickListener {
-        private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
-
-        Launcher(PendingIntent intent, String pkg, String tag, int id) {
-            mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
-        }
-
-        public void onClick(View v) {
-            try {
-                // The intent we are sending is for the application, which
-                // won't have permission to immediately start an activity after
-                // the user switches to home.  We know it is safe to do at this
-                // point, so make sure new activity switches are now allowed.
-                ActivityManagerNative.getDefault().resumeAppSwitches();
-            } catch (RemoteException e) {
-            }
-            int[] pos = new int[2];
-            v.getLocationOnScreen(pos);
-            Intent overlay = new Intent();
-            overlay.setSourceBounds(
-                    new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
-            try {
-                mIntent.send(mContext, 0, overlay);
-                mNotificationCallbacks.onNotificationClick(mPkg, mTag, mId);
-            } catch (PendingIntent.CanceledException e) {
-                // the stack trace isn't very helpful here.  Just log the exception message.
-                Slog.w(TAG, "Sending contentIntent failed: " + e);
-            }
-            deactivate();
-        }
-    }
-
-    private class MyTicker extends Ticker {
-        MyTicker(Context context, StatusBarView sb) {
-            super(context, sb);
-        }
-        
-        @Override
-        void tickerStarting() {
-            mTicking = true;
-            mIcons.setVisibility(View.GONE);
-            mTickerView.setVisibility(View.VISIBLE);
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
-            if (mExpandedVisible) {
-                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
-            }
-        }
-
-        @Override
-        void tickerDone() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
-            }
-        }
-
-        void tickerHalting() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-            }
-        }
-    }
-
-    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
-        public void onAnimationEnd(Animation animation) {
-            mTicking = false;
-        }
-        public void onAnimationRepeat(Animation animation) {
-        }
-        public void onAnimationStart(Animation animation) {
-        }
-    };
-
-    private Animation loadAnim(int id, Animation.AnimationListener listener) {
-        Animation anim = AnimationUtils.loadAnimation(mContext, id);
-        if (listener != null) {
-            anim.setAnimationListener(listener);
-        }
-        return anim;
-    }
-
-    public String viewInfo(View v) {
-        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
-                + " " + v.getWidth() + "x" + v.getHeight() + ")";
-    }
-
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump StatusBar from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-        
-        synchronized (mQueueLock) {
-            pw.println("Current Status Bar state:");
-            pw.println("  mExpanded=" + mExpanded
-                    + ", mExpandedVisible=" + mExpandedVisible);
-            pw.println("  mTicking=" + mTicking);
-            pw.println("  mTracking=" + mTracking);
-            pw.println("  mAnimating=" + mAnimating
-                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
-                    + ", mAnimAccel=" + mAnimAccel);
-            pw.println("  mCurAnimationTime=" + mCurAnimationTime
-                    + " mAnimLastTime=" + mAnimLastTime);
-            pw.println("  mDisplayHeight=" + mDisplayHeight
-                    + " mAnimatingReveal=" + mAnimatingReveal
-                    + " mViewDelta=" + mViewDelta);
-            pw.println("  mDisplayHeight=" + mDisplayHeight);
-            final int N = mQueue.size();
-            pw.println("  mQueue.size=" + N);
-            for (int i=0; i<N; i++) {
-                PendingOp op = mQueue.get(i);
-                pw.println("    [" + i + "] key=" + op.key + " code=" + op.code + " visible="
-                        + op.visible);
-                pw.println("           iconData=" + op.iconData);
-                pw.println("           notificationData=" + op.notificationData);
-            }
-            pw.println("  mExpandedParams: " + mExpandedParams);
-            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
-            pw.println("  mExpandedDialog: " + mExpandedDialog);
-            pw.println("  mTrackingParams: " + mTrackingParams);
-            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
-            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
-            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
-            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
-            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
-            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
-            pw.println("  mCloseView: " + viewInfo(mCloseView));
-            pw.println("  mTickerView: " + viewInfo(mTickerView));
-            pw.println("  mScrollView: " + viewInfo(mScrollView)
-                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
-            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
-        }
-        synchronized (mIconMap) {
-            final int N = mIconMap.size();
-            pw.println("  mIconMap.size=" + N);
-            Set<IBinder> keys = mIconMap.keySet();
-            int i=0;
-            for (IBinder key: keys) {
-                StatusBarIcon icon = mIconMap.get(key);
-                pw.println("    [" + i + "] key=" + key);
-                pw.println("           data=" + icon.mData);
-                i++;
-            }
-        }
-        synchronized (mNotificationData) {
-            int N = mNotificationData.ongoingCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getOngoing(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-            N = mNotificationData.latestCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getLatest(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-        }
-        synchronized (mDisableRecords) {
-            final int N = mDisableRecords.size();
-            pw.println("  mDisableRecords.size=" + N
-                    + " mDisabled=0x" + Integer.toHexString(mDisabled));
-            for (int i=0; i<N; i++) {
-                DisableRecord tok = mDisableRecords.get(i);
-                pw.println("    [" + i + "] what=0x" + Integer.toHexString(tok.what)
-                                + " pkg=" + tok.pkg + " token=" + tok.token);
-            }
-        }
-        
-        if (false) {
-            pw.println("see the logcat for a dump of the views we have created.");
-            // must happen on ui thread
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        mStatusBarView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mStatusBarView.getWidth() + "x"
-                                + mStatusBarView.getHeight());
-                        mStatusBarView.debug();
-
-                        mExpandedView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mExpandedView.getWidth() + "x"
-                                + mExpandedView.getHeight());
-                        mExpandedView.debug();
-
-                        mTrackingView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mTrackingView.getWidth() + "x"
-                                + mTrackingView.getHeight());
-                        mTrackingView.debug();
-                    }
-                });
-        }
-    }
-
-    void onBarViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Tracking View --------------
-        pixelFormat = PixelFormat.RGBX_8888;
-        bg = mTrackingView.getBackground();
-        if (bg != null) {
-            pixelFormat = bg.getOpacity();
-        }
-
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                pixelFormat);
-//        lp.token = mStatusBarView.getWindowToken();
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("TrackingView");
-        lp.y = mTrackingPosition;
-        mTrackingParams = lp;
-
-        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
-    }
-
-    void onTrackingViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Expanded View --------------
-        pixelFormat = PixelFormat.TRANSLUCENT;
-
-        final int disph = mDisplay.getHeight();
-        lp = mExpandedDialog.getWindow().getAttributes();
-        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        lp.height = getExpandedHeight();
-        lp.x = 0;
-        mTrackingPosition = lp.y = -disph; // sufficiently large negative
-        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_DITHER
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.format = pixelFormat;
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBarExpanded");
-        mExpandedDialog.getWindow().setAttributes(lp);
-        mExpandedDialog.getWindow().setFormat(pixelFormat);
-        mExpandedParams = lp;
-
-        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        mExpandedDialog.setContentView(mExpandedView,
-                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                           ViewGroup.LayoutParams.MATCH_PARENT));
-        mExpandedDialog.getWindow().setBackgroundDrawable(null);
-        mExpandedDialog.show();
-        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
-    }
-
-    void setDateViewVisibility(boolean visible, int anim) {
-        mDateView.setUpdates(visible);
-        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-        mDateView.startAnimation(loadAnim(anim, null));
-    }
-
-    void setNotificationIconVisibility(boolean visible, int anim) {
-        int old = mNotificationIcons.getVisibility();
-        int v = visible ? View.VISIBLE : View.INVISIBLE;
-        if (old != v) {
-            mNotificationIcons.setVisibility(v);
-            mNotificationIcons.startAnimation(loadAnim(anim, null));
-        }
-    }
-
-    void updateExpandedViewPos(int expandedPosition) {
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition);
-        }
-
-        int h = mStatusBarView.getHeight();
-        int disph = mDisplay.getHeight();
-
-        // If the expanded view is not visible, make sure they're still off screen.
-        // Maybe the view was resized.
-        if (!mExpandedVisible) {
-            if (mTrackingView != null) {
-                mTrackingPosition = -disph;
-                if (mTrackingParams != null) {
-                    mTrackingParams.y = mTrackingPosition;
-                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-                }
-            }
-            if (mExpandedParams != null) {
-                mExpandedParams.y = -disph;
-                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-            }
-            return;
-        }
-
-        // tracking view...
-        int pos;
-        if (expandedPosition == EXPANDED_FULL_OPEN) {
-            pos = h;
-        }
-        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
-            pos = mTrackingPosition;
-        }
-        else {
-            if (expandedPosition <= disph) {
-                pos = expandedPosition;
-            } else {
-                pos = disph;
-            }
-            pos -= disph-h;
-        }
-        mTrackingPosition = mTrackingParams.y = pos;
-        mTrackingParams.height = disph-h;
-        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-
-        if (mExpandedParams != null) {
-            mCloseView.getLocationInWindow(mPositionTmp);
-            final int closePos = mPositionTmp[1];
-
-            mExpandedContents.getLocationInWindow(mPositionTmp);
-            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
-
-            mExpandedParams.y = pos + mTrackingView.getHeight()
-                    - (mTrackingParams.height-closePos) - contentsBottom;
-            int max = h;
-            if (mExpandedParams.y > max) {
-                mExpandedParams.y = max;
-            }
-            int min = mTrackingPosition;
-            if (mExpandedParams.y < min) {
-                mExpandedParams.y = min;
-            }
-
-            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
-            if (!visible) {
-                // if the contents aren't visible, move the expanded view way off screen
-                // because the window itself extends below the content view.
-                mExpandedParams.y = -disph;
-            }
-            panelSlightlyVisible(visible);
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        }
-
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition
-                    + " mExpandedParams.y=" + mExpandedParams.y
-                    + " mExpandedParams.height=" + mExpandedParams.height);
-        }
-    }
-
-    int getExpandedHeight() {
-        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
-    }
-
-    void updateExpandedHeight() {
-        if (mExpandedView != null) {
-            mExpandedParams.height = getExpandedHeight();
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        }
-    }
-
-    /**
-     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
-     * This was added last-minute and is inconsistent with the way the rest of the notifications
-     * are handled, because the notification isn't really cancelled.  The lights are just
-     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
-     * this is what he wants. (see bug 1131461)
-     */
-    private boolean mPanelSlightlyVisible;
-    void panelSlightlyVisible(boolean visible) {
-        if (mPanelSlightlyVisible != visible) {
-            mPanelSlightlyVisible = visible;
-            if (visible) {
-                // tell the notification manager to turn off the lights.
-                mNotificationCallbacks.onPanelRevealed();
-            }
-        }
-    }
-
-    void performDisableActions(int net) {
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mNotificationIcons.setVisibility(View.INVISIBLE);
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
-            }
-        }
-    }
-
-    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            mNotificationCallbacks.onClearAll();
-            addPendingOp(OP_EXPAND, null, false);
-        }
-    };
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                deactivate();
-            }
-            else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
-                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
-                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
-            }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                updateResources();
-            }
-        }
-    };
-
-    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-        if (false) {
-            Slog.d(TAG, "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
-        }
-        boolean something = false;
-        if (showPlmn) {
-            mPlmnLabel.setVisibility(View.VISIBLE);
-            if (plmn != null) {
-                mPlmnLabel.setText(plmn);
-            } else {
-                mPlmnLabel.setText(R.string.lockscreen_carrier_default);
-            }
-        } else {
-            mPlmnLabel.setText("");
-            mPlmnLabel.setVisibility(View.GONE);
-        }
-        if (showSpn && spn != null) {
-            mSpnLabel.setText(spn);
-            mSpnLabel.setVisibility(View.VISIBLE);
-            something = true;
-        } else {
-            mSpnLabel.setText("");
-            mSpnLabel.setVisibility(View.GONE);
-        }
-    }
-
-    /**
-     * Reload some of our resources when the configuration changes.
-     * 
-     * We don't reload everything when the configuration changes -- we probably
-     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
-     * meantime, just update the things that we know change.
-     */
-    void updateResources() {
-        Resources res = mContext.getResources();
-
-        mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button));
-        mOngoingTitle.setText(mContext.getText(R.string.status_bar_ongoing_events_title));
-        mLatestTitle.setText(mContext.getText(R.string.status_bar_latest_events_title));
-        mNoNotificationsTitle.setText(mContext.getText(R.string.status_bar_no_notifications_title));
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        if (false) Slog.v(TAG, "updateResources");
-    }
-
-    //
-    // tracing
-    //
-
-    void postStartTracing() {
-        mHandler.postDelayed(mStartTracing, 3000);
-    }
-
-    void vibrate() {
-        android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
-                Context.VIBRATOR_SERVICE);
-        vib.vibrate(250);
-    }
-
-    Runnable mStartTracing = new Runnable() {
-        public void run() {
-            vibrate();
-            SystemClock.sleep(250);
-            Slog.d(TAG, "startTracing");
-            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
-            mHandler.postDelayed(mStopTracing, 10000);
-        }
-    };
-
-    Runnable mStopTracing = new Runnable() {
-        public void run() {
-            android.os.Debug.stopMethodTracing();
-            Slog.d(TAG, "stopTracing");
-            vibrate();
-        }
-    };
-    
-    class UninstallReceiver extends BroadcastReceiver {
-        public UninstallReceiver() {
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
-            filter.addDataScheme("package");
-            mContext.registerReceiver(this, filter);
-            IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-            mContext.registerReceiver(this, sdFilter);
-        }
-        
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String pkgList[] = null;
-            if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
-                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-            } else {
-                Uri data = intent.getData();
-                if (data != null) {
-                    String pkg = data.getSchemeSpecificPart();
-                    if (pkg != null) {
-                        pkgList = new String[]{pkg};
-                    }
-                }
-            }
-            ArrayList<StatusBarNotification> list = null;
-            if (pkgList != null) {
-                synchronized (StatusBarService.this) {
-                    for (String pkg : pkgList) {
-                        list = mNotificationData.notificationsForPackage(pkg);
-                    }
-                }
-            }
-            
-            if (list != null) {
-                final int N = list.size();
-                for (int i=0; i<N; i++) {
-                    removeIcon(list.get(i).key);
-                }
-            }
-        }
-    }
-}
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index fcb9d55..d9262f6 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -147,9 +147,6 @@
      * @param intent The Intent as if supplied to {@link android.content.Context#startService}.
      */
     protected void startService(Intent intent) {
-        assertFalse(mServiceStarted);
-        assertFalse(mServiceBound);
-        
         if (!mServiceAttached) {
             setupService();
         }
@@ -159,7 +156,7 @@
             mService.onCreate();
             mServiceCreated = true;
         }
-        mService.onStart(intent, mServiceId);
+        mService.onStartCommand(intent, 0, mServiceId);
         
         mServiceStarted = true;
     }
@@ -183,9 +180,6 @@
      * @return Return an IBinder for making further calls into the Service.
      */
     protected IBinder bindService(Intent intent) {
-        assertFalse(mServiceStarted);
-        assertFalse(mServiceBound);
-        
         if (!mServiceAttached) {
             setupService();
         }
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index ffd757c..c31c9cc 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
@@ -184,6 +185,12 @@
     }
 
     @Override
+    public SQLiteDatabase openOrCreateDatabase(String file, int mode,
+            SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public File getDatabasePath(String name) {
         throw new UnsupportedOperationException();
     }
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index c817532..baa150a 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -191,4 +191,8 @@
     public void unregisterDataSetObserver(DataSetObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
+
+    public int getType(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
 }
\ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index dc0c23b..3c992e9 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -105,6 +105,7 @@
         ignoreResultList.add("http/tests/xmlhttprequest/workers"); // workers not supported
         ignoreResultList.add("storage/domstorage/localstorage/private-browsing-affects-storage.html"); // private browsing not supported
         ignoreResultList.add("storage/domstorage/sessionstorage/private-browsing-affects-storage.html"); // private browsing not supported
+        ignoreResultList.add("storage/indexeddb"); // indexeddb not supported
         ignoreResultList.add("storage/private-browsing-readonly.html"); // private browsing not supported
         ignoreResultList.add("websocket/tests/workers"); // workers not supported
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 322b0d2..0883387 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -42,8 +42,13 @@
         //no creation of instances
     }
 
-    public static void findLayoutTestsRecursively(BufferedOutputStream bos,
+    /**
+     * @return the number of tests in the list.
+     */
+    public static int writeLayoutTestListRecursively(BufferedOutputStream bos,
             String dir, boolean ignoreResultsInDir) throws IOException {
+
+        int testCount = 0;
         Log.v(LOGTAG, "Searching tests under " + dir);
 
         File d = new File(dir);
@@ -61,7 +66,7 @@
                 // If this is not a test directory, we don't recurse into it.
                 if (!FileFilter.isNonTestDir(s)) {
                     Log.v(LOGTAG, "Recursing on " + s);
-                    findLayoutTestsRecursively(bos, s, ignoreResultsInDir);
+                    testCount += writeLayoutTestListRecursively(bos, s, ignoreResultsInDir);
                 }
                 continue;
             }
@@ -81,8 +86,10 @@
                     bos.write((" IGNORE_RESULT").getBytes());
                 }
                 bos.write('\n');
+                testCount++;
             }
         }
+        return testCount;
     }
 
     public static void updateTestStatus(String statusFile, String s) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a2809c3..fabbf89 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -290,7 +290,7 @@
         }
     }
 
-    private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult, int testIndex) {
+    private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult, int testNumber) {
         activity.setCallback(new TestShellCallback() {
             public void finished() {
                 synchronized (LayoutTestsAutoTest.this) {
@@ -326,8 +326,8 @@
         intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test));
         intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
         intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
-        intent.putExtra(TestShellActivity.TEST_COUNT, mTestCount);
-        intent.putExtra(TestShellActivity.TEST_INDEX, testIndex);
+        intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, mTestCount);
+        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, testNumber);
         activity.startActivity(intent);
 
         // Wait until done.
@@ -402,7 +402,9 @@
             boolean ignoreResult = mTestListIgnoreResult.elementAt(i);
             FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
             // Run tests
-            runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult, i + mResumeIndex);
+            // i is 0 based, but test count is 1 based so add 1 to i here.
+            runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult,
+                    i + 1 + mResumeIndex);
         }
 
         FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
@@ -427,7 +429,7 @@
         try {
             File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
-            FsUtils.findLayoutTestsRecursively(bos, getTestPath(), false); // Don't ignore results
+            FsUtils.writeLayoutTestListRecursively(bos, getTestPath(), false); // Don't ignore results
             bos.flush();
             bos.close();
        } catch (Exception e) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
index 82671eb..5ffe6b0 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -51,29 +51,38 @@
         intent.setClass(this, TestShellActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
         intent.putExtra(TestShellActivity.TEST_URL, "file://" + filename);
+        intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, 1);
+        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 1);
         startActivity(intent);
     }
 
     @Override
     void processDirectory(String path, boolean selection) {
-        generateTestList(path);
+        int testCount = generateTestList(path);
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setClass(this, TestShellActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
         intent.putExtra(TestShellActivity.UI_AUTO_TEST, LAYOUT_TESTS_LIST_FILE);
+        intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, testCount);
+        // TestShellActivity will process this intent once and increment the test index
+        // before running the first test, so pass 0 here to allow for that.
+        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 0);
         startActivity(intent);
     }
 
-    private void generateTestList(String path) {
+    private int generateTestList(String path) {
+        int testCount = 0;
         try {
             File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
-            FsUtils.findLayoutTestsRecursively(bos, path, false); // Don't ignore results
+            testCount = FsUtils.writeLayoutTestListRecursively(
+                    bos, path, false); // Don't ignore results
             bos.flush();
             bos.close();
        } catch (Exception e) {
            Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
        }
+       return testCount;
     }
 
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 5b4cf22..31cbf03 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -34,6 +34,7 @@
 import android.os.Message;
 import android.util.Log;
 import android.view.ViewGroup;
+import android.view.Window;
 import android.webkit.ConsoleMessage;
 import android.webkit.GeolocationPermissions;
 import android.webkit.HttpAuthHandler;
@@ -117,6 +118,7 @@
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
+        requestWindowFeature(Window.FEATURE_PROGRESS);
 
         LinearLayout contentView = new LinearLayout(this);
         contentView.setOrientation(LinearLayout.VERTICAL);
@@ -159,6 +161,9 @@
             return;
         }
 
+        mTotalTestCount = intent.getIntExtra(TOTAL_TEST_COUNT, mTotalTestCount);
+        mCurrentTestNumber = intent.getIntExtra(CURRENT_TEST_NUMBER, mCurrentTestNumber);
+
         mTestUrl = intent.getStringExtra(TEST_URL);
         if (mTestUrl == null) {
             mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST);
@@ -172,9 +177,10 @@
         mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
         mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false);
         mSaveImagePath = intent.getStringExtra(SAVE_IMAGE);
-        mTestCount = intent.getIntExtra(TEST_COUNT, 0);
-        mTestIndex = intent.getIntExtra(TEST_INDEX, 0);
-        setTitle("Test " + (mTestIndex + 1) + " of " + mTestCount);
+        setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount);
+        float ratio = (float)mCurrentTestNumber / mTotalTestCount;
+        int progress = (int)(ratio * Window.PROGRESS_END);
+        getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress);
 
         Log.v(LOGTAG, "  Loading " + mTestUrl);
         mWebView.loadUrl(mTestUrl);
@@ -240,6 +246,7 @@
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
         intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
+        intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, ++mCurrentTestNumber);
         intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
         executeIntent(intent);
     }
@@ -574,7 +581,7 @@
 
         @Override
         public void onReceivedTitle(WebView view, String title) {
-            setTitle("Test " + (mTestIndex + 1) + " of " + mTestCount + ": "+ title);
+            setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount + ": "+ title);
             if (mDumpTitleChanges) {
                 mTitleChanges.append("TITLE CHANGED: ");
                 mTitleChanges.append(title);
@@ -843,8 +850,8 @@
     private String mSaveImagePath;
     private BufferedReader mTestListReader;
     private boolean mGetDrawtime;
-    private int mTestCount;
-    private int mTestIndex;
+    private int mTotalTestCount;
+    private int mCurrentTestNumber;
 
     // States
     private boolean mTimedOut;
@@ -882,8 +889,8 @@
     static final String UI_AUTO_TEST = "UiAutoTest";
     static final String GET_DRAW_TIME = "GetDrawTime";
     static final String SAVE_IMAGE = "SaveImage";
-    static final String TEST_COUNT = "TestCount";
-    static final String TEST_INDEX = "TestIndex";
+    static final String TOTAL_TEST_COUNT = "TestCount";
+    static final String CURRENT_TEST_NUMBER = "TestNumber";
 
     static final int DRAW_RUNS = 5;
     static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt";
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index e7a09d1..3602fec 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -21,6 +21,7 @@
 import android.widget.ArrayAdapter;
 import android.view.View;
 import android.widget.ListView;
+import android.content.Context;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.app.Notification;
@@ -60,7 +61,7 @@
     private Test[] mTests = new Test[] {
         new Test("Off and sound") {
             public void run() {
-                PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService("power");
+                PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
                 PowerManager.WakeLock wl = 
                             pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "sound");
                 wl.acquire();
@@ -121,6 +122,16 @@
             }
         },
 
+        new Test("Bad Icon") {
+            public void run() {
+                mNM.notify(1, new Notification(NotificationTestList.this,
+                            R.layout.chrono_notification, /* not a drawable! */
+                            null, System.currentTimeMillis()-(1000*60*60*24),
+                            "(453) 123-2328",
+                            "", null));
+            }
+        },
+
         new Test("Bad resource #2") {
             public void run()
             {
@@ -180,7 +191,7 @@
                                 R.drawable.icon4,
                                 null, System.currentTimeMillis(), "Stress - Latest",
                                 "Notify me!!!", null);
-                        n.flags |= Notification.FLAG_ONGOING_EVENT;
+                        //n.flags |= Notification.FLAG_ONGOING_EVENT;
                         mNM.notify(1, n);
                     }
                 }
@@ -599,7 +610,7 @@
             public void run()
             {
                 PowerManager.WakeLock wl
-                        = ((PowerManager)NotificationTestList.this.getSystemService("power"))
+                        = ((PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE))
                             .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher");
                 wl.acquire();
                 mHandler.postDelayed(new Runnable() {
@@ -622,9 +633,7 @@
 
     private PendingIntent makeIntent() {
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setComponent(new android.content.ComponentName(
-                    "com.android.contacts",
-                    "com.android.contacts.ContactsActivity"));
+        intent.addCategory(Intent.CATEGORY_HOME);
         return PendingIntent.getActivity(this, 0, intent, 0);
     }
 
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 06506fb..3532e30 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -134,13 +134,9 @@
                     }, 3000);
             }
         },
-        new Test("Expand in 3 sec.") {
+        new Test("Expand") {
             public void run() {
-                mHandler.postDelayed(new Runnable() {
-                        public void run() {
-                            mStatusBarManager.expand();
-                        }
-                    }, 3000);
+                mStatusBarManager.expand();
             }
         },
         new Test("Expand in 3 sec.") {
@@ -161,14 +157,5 @@
                     }, 3000);
             }
         },
-        new Test("Toggle in 3 sec.") {
-            public void run() {
-                mHandler.postDelayed(new Runnable() {
-                        public void run() {
-                            mStatusBarManager.toggle();
-                        }
-                    }, 3000);
-            }
-        },
     };
 }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a2f085a..755b93b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -573,6 +573,7 @@
                         const String16& parentIdent,
                         const String16& itemIdent,
                         int32_t curFormat,
+                        bool isFormatted,
                         bool pseudolocalize,
                         const bool overwrite,
                         ResourceTable* outTable)
@@ -583,7 +584,7 @@
     String16 str;
     Vector<StringPool::entry_style_span> spans;
     err = parseStyledString(bundle, in->getPrintableSource().string(),
-                            block, item16, &str, &spans,
+                            block, item16, &str, &spans, isFormatted,
                             pseudolocalize);
     if (err != NO_ERROR) {
         return err;
@@ -616,6 +617,7 @@
                         const String16& curTag,
                         bool curIsStyled,
                         int32_t curFormat,
+                        bool isFormatted,
                         bool pseudolocalize,
                         const bool overwrite,
                         ResourceTable* outTable)
@@ -626,7 +628,7 @@
     Vector<StringPool::entry_style_span> spans;
     err = parseStyledString(bundle, in->getPrintableSource().string(), block,
                             curTag, &str, curIsStyled ? &spans : NULL,
-                            pseudolocalize);
+                            isFormatted, pseudolocalize);
 
     if (err < NO_ERROR) { 
         return err;
@@ -709,12 +711,18 @@
     // useful attribute names and special values
     const String16 name16("name");
     const String16 translatable16("translatable");
+    const String16 formatted16("formatted");
     const String16 false16("false");
 
     const String16 myPackage(assets->getPackage());
 
     bool hasErrors = false;
-    
+
+    bool fileIsTranslatable = true;
+    if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) {
+        fileIsTranslatable = false;
+    }
+
     DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
 
     ResXMLTree::event_code_t code;
@@ -751,6 +759,7 @@
             bool curIsBagReplaceOnOverwrite = false;
             bool curIsStyled = false;
             bool curIsPseudolocalizable = false;
+            bool curIsFormatted = fileIsTranslatable;
             bool localHasErrors = false;
 
             if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
@@ -1136,6 +1145,7 @@
                 String8 locale(rawLocale);
                 String16 name;
                 String16 translatable;
+                String16 formatted;
 
                 size_t n = block.getAttributeCount();
                 for (size_t i = 0; i < n; i++) {
@@ -1145,11 +1155,14 @@
                         name.setTo(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, translatable16.string()) == 0) {
                         translatable.setTo(block.getAttributeStringValue(i, &length));
+                    } else if (strcmp16(attr, formatted16.string()) == 0) {
+                        formatted.setTo(block.getAttributeStringValue(i, &length));
                     }
                 }
                 
                 if (name.size() > 0) {
                     if (translatable == false16) {
+                        curIsFormatted = false;
                         // Untranslatable strings must only exist in the default [empty] locale
                         if (locale.size() > 0) {
                             fprintf(stderr, "aapt: warning: string '%s' in %s marked untranslatable but exists"
@@ -1167,6 +1180,10 @@
                     } else {
                         outTable->addLocalization(name, locale);
                     }
+
+                    if (formatted == false16) {
+                        curIsFormatted = false;
+                    }
                 }
 
                 curTag = &string16;
@@ -1356,7 +1373,7 @@
                         block.getPosition(&parserPosition);
 
                         err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
-                                ident, parentIdent, itemIdent, curFormat, 
+                                ident, parentIdent, itemIdent, curFormat, curIsFormatted,
                                 false, overwrite, outTable);
                         if (err == NO_ERROR) {
                             if (curIsPseudolocalizable && localeIsDefined(curParams)
@@ -1365,8 +1382,8 @@
 #if 1
                                 block.setPosition(parserPosition);
                                 err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
-                                        curType, ident, parentIdent, itemIdent, curFormat, true,
-                                        overwrite, outTable);
+                                        curType, ident, parentIdent, itemIdent, curFormat,
+                                        curIsFormatted, true, overwrite, outTable);
 #endif
                             }
                         } 
@@ -1389,7 +1406,8 @@
                 block.getPosition(&parserPosition);
 
                 err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
-                        *curTag, curIsStyled, curFormat, false, overwrite, outTable);
+                        *curTag, curIsStyled, curFormat, curIsFormatted,
+                        false, overwrite, outTable);
 
                 if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
                     hasErrors = localHasErrors = true;
@@ -1400,7 +1418,8 @@
                         // pseudolocalize here
                         block.setPosition(parserPosition);
                         err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
-                                ident, *curTag, curIsStyled, curFormat, true, overwrite, outTable);
+                                ident, *curTag, curIsStyled, curFormat,
+                                curIsFormatted, true, overwrite, outTable);
                         if (err != NO_ERROR) {
                             hasErrors = localHasErrors = true;
                         }
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 4c59288..57ff47a 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -68,12 +68,118 @@
     return String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize);
 }
 
+status_t hasSubstitutionErrors(const char* fileName,
+                               ResXMLTree* inXml,
+                               String16 str16)
+{
+    const char16_t* str = str16.string();
+    const char16_t* p = str;
+    const char16_t* end = str + str16.size();
+
+    bool nonpositional = false;
+    int argCount = 0;
+
+    while (p < end) {
+        /*
+         * Look for the start of a Java-style substitution sequence.
+         */
+        if (*p == '%' && p + 1 < end) {
+            p++;
+
+            // A literal percent sign represented by %%
+            if (*p == '%') {
+                p++;
+                continue;
+            }
+
+            argCount++;
+
+            if (*p >= '0' && *p <= '9') {
+                do {
+                    p++;
+                } while (*p >= '0' && *p <= '9');
+                if (*p != '$') {
+                    // This must be a size specification instead of position.
+                    nonpositional = true;
+                }
+            } else if (*p == '<') {
+                // Reusing last argument; bad idea since it can be re-arranged.
+                nonpositional = true;
+                p++;
+
+                // Optionally '$' can be specified at the end.
+                if (p < end && *p == '$') {
+                    p++;
+                }
+            } else {
+                nonpositional = true;
+            }
+
+            // Ignore flags and widths
+            while (p < end && (*p == '-' ||
+                    *p == '#' ||
+                    *p == '+' ||
+                    *p == ' ' ||
+                    *p == ',' ||
+                    *p == '(' ||
+                    (*p >= '0' && *p <= '9'))) {
+                p++;
+            }
+
+            /*
+             * This is a shortcut to detect strings that are going to Time.format()
+             * instead of String.format()
+             *
+             * Comparison of String.format() and Time.format() args:
+             *
+             * String: ABC E GH  ST X abcdefgh  nost x
+             *   Time:    DEFGHKMS W Za  d   hkm  s w yz
+             *
+             * Therefore we know it's definitely Time if we have:
+             *     DFKMWZkmwyz
+             */
+            if (p < end) {
+                switch (*p) {
+                case 'D':
+                case 'F':
+                case 'K':
+                case 'M':
+                case 'W':
+                case 'Z':
+                case 'k':
+                case 'm':
+                case 'w':
+                case 'y':
+                case 'z':
+                    return NO_ERROR;
+                }
+            }
+        }
+
+        p++;
+    }
+
+    /*
+     * If we have more than one substitution in this string and any of them
+     * are not in positional form, give the user an error.
+     */
+    if (argCount > 1 && nonpositional) {
+        SourcePos(String8(fileName), inXml->getLineNumber()).error(
+                "Multiple substitutions specified in non-positional format; "
+                "did you mean to add the formatted=\"true\" attribute?\n");
+        return NOT_ENOUGH_DATA;
+    }
+
+    return NO_ERROR;
+}
+
 status_t parseStyledString(Bundle* bundle,
                            const char* fileName,
                            ResXMLTree* inXml,
                            const String16& endTag,
                            String16* outString,
                            Vector<StringPool::entry_style_span>* outSpans,
+                           bool isFormatted,
                            bool pseudolocalize)
 {
     Vector<StringPool::entry_style_span> spanStack;
@@ -101,7 +207,11 @@
                 std::string pseudo = pseudolocalize_string(orig);
                 curString.append(String16(String8(pseudo.c_str())));
             } else {
-                curString.append(text);
+                if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) {
+                    return UNKNOWN_ERROR;
+                } else {
+                    curString.append(text);
+                }
             }
         } else if (code == ResXMLTree::START_TAG) {
             const String16 element16(inXml->getElementName(&len));
diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h
index e9a263b..05624b7 100644
--- a/tools/aapt/XMLNode.h
+++ b/tools/aapt/XMLNode.h
@@ -25,6 +25,7 @@
                            const String16& endTag,
                            String16* outString,
                            Vector<StringPool::entry_style_span>* outSpans,
+                           bool isFormatted,
                            bool isPseudolocalizable);
 
 void printXMLBlock(ResXMLTree* block);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index 744bfbe6..58b1b6c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -37,6 +37,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
+import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
@@ -1059,6 +1060,13 @@
     }
 
     @Override
+    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
+            CursorFactory arg2, DatabaseErrorHandler arg3) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
     public Drawable peekWallpaper() {
         // TODO Auto-generated method stub
         return null;
diff --git a/vcard/Android.mk b/vcard/Android.mk
deleted file mode 100644
index 2bc17aa..0000000
--- a/vcard/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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_MODULE := com.android.vcard
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-# Use google-common instead of android-common for using hidden code in telephony library.
-# Use ext for using Quoted-Printable codec.
-LOCAL_JAVA_LIBRARIES := google-common ext
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Build the test package.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/vcard/java/com/android/vcard/JapaneseUtils.java b/vcard/java/com/android/vcard/JapaneseUtils.java
deleted file mode 100644
index 5b44944..0000000
--- a/vcard/java/com/android/vcard/JapaneseUtils.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.vcard;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * TextUtils especially for Japanese.
- */
-/* package */ class JapaneseUtils {
-    static private final Map<Character, String> sHalfWidthMap =
-        new HashMap<Character, String>();
-
-    static {
-        sHalfWidthMap.put('\u3001', "\uFF64");
-        sHalfWidthMap.put('\u3002', "\uFF61");
-        sHalfWidthMap.put('\u300C', "\uFF62");
-        sHalfWidthMap.put('\u300D', "\uFF63");
-        sHalfWidthMap.put('\u301C', "~");
-        sHalfWidthMap.put('\u3041', "\uFF67");
-        sHalfWidthMap.put('\u3042', "\uFF71");
-        sHalfWidthMap.put('\u3043', "\uFF68");
-        sHalfWidthMap.put('\u3044', "\uFF72");
-        sHalfWidthMap.put('\u3045', "\uFF69");
-        sHalfWidthMap.put('\u3046', "\uFF73");
-        sHalfWidthMap.put('\u3047', "\uFF6A");
-        sHalfWidthMap.put('\u3048', "\uFF74");
-        sHalfWidthMap.put('\u3049', "\uFF6B");
-        sHalfWidthMap.put('\u304A', "\uFF75");
-        sHalfWidthMap.put('\u304B', "\uFF76");
-        sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
-        sHalfWidthMap.put('\u304D', "\uFF77");
-        sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
-        sHalfWidthMap.put('\u304F', "\uFF78");
-        sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
-        sHalfWidthMap.put('\u3051', "\uFF79");
-        sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
-        sHalfWidthMap.put('\u3053', "\uFF7A");
-        sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
-        sHalfWidthMap.put('\u3055', "\uFF7B");
-        sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
-        sHalfWidthMap.put('\u3057', "\uFF7C");
-        sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
-        sHalfWidthMap.put('\u3059', "\uFF7D");
-        sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
-        sHalfWidthMap.put('\u305B', "\uFF7E");
-        sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
-        sHalfWidthMap.put('\u305D', "\uFF7F");
-        sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
-        sHalfWidthMap.put('\u305F', "\uFF80");
-        sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
-        sHalfWidthMap.put('\u3061', "\uFF81");
-        sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
-        sHalfWidthMap.put('\u3063', "\uFF6F");
-        sHalfWidthMap.put('\u3064', "\uFF82");
-        sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
-        sHalfWidthMap.put('\u3066', "\uFF83");
-        sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
-        sHalfWidthMap.put('\u3068', "\uFF84");
-        sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
-        sHalfWidthMap.put('\u306A', "\uFF85");
-        sHalfWidthMap.put('\u306B', "\uFF86");
-        sHalfWidthMap.put('\u306C', "\uFF87");
-        sHalfWidthMap.put('\u306D', "\uFF88");
-        sHalfWidthMap.put('\u306E', "\uFF89");
-        sHalfWidthMap.put('\u306F', "\uFF8A");
-        sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
-        sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
-        sHalfWidthMap.put('\u3072', "\uFF8B");
-        sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
-        sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
-        sHalfWidthMap.put('\u3075', "\uFF8C");
-        sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
-        sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
-        sHalfWidthMap.put('\u3078', "\uFF8D");
-        sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
-        sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
-        sHalfWidthMap.put('\u307B', "\uFF8E");
-        sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
-        sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
-        sHalfWidthMap.put('\u307E', "\uFF8F");
-        sHalfWidthMap.put('\u307F', "\uFF90");
-        sHalfWidthMap.put('\u3080', "\uFF91");
-        sHalfWidthMap.put('\u3081', "\uFF92");
-        sHalfWidthMap.put('\u3082', "\uFF93");
-        sHalfWidthMap.put('\u3083', "\uFF6C");
-        sHalfWidthMap.put('\u3084', "\uFF94");
-        sHalfWidthMap.put('\u3085', "\uFF6D");
-        sHalfWidthMap.put('\u3086', "\uFF95");
-        sHalfWidthMap.put('\u3087', "\uFF6E");
-        sHalfWidthMap.put('\u3088', "\uFF96");
-        sHalfWidthMap.put('\u3089', "\uFF97");
-        sHalfWidthMap.put('\u308A', "\uFF98");
-        sHalfWidthMap.put('\u308B', "\uFF99");
-        sHalfWidthMap.put('\u308C', "\uFF9A");
-        sHalfWidthMap.put('\u308D', "\uFF9B");
-        sHalfWidthMap.put('\u308E', "\uFF9C");
-        sHalfWidthMap.put('\u308F', "\uFF9C");
-        sHalfWidthMap.put('\u3090', "\uFF72");
-        sHalfWidthMap.put('\u3091', "\uFF74");
-        sHalfWidthMap.put('\u3092', "\uFF66");
-        sHalfWidthMap.put('\u3093', "\uFF9D");
-        sHalfWidthMap.put('\u309B', "\uFF9E");
-        sHalfWidthMap.put('\u309C', "\uFF9F");
-        sHalfWidthMap.put('\u30A1', "\uFF67");
-        sHalfWidthMap.put('\u30A2', "\uFF71");
-        sHalfWidthMap.put('\u30A3', "\uFF68");
-        sHalfWidthMap.put('\u30A4', "\uFF72");
-        sHalfWidthMap.put('\u30A5', "\uFF69");
-        sHalfWidthMap.put('\u30A6', "\uFF73");
-        sHalfWidthMap.put('\u30A7', "\uFF6A");
-        sHalfWidthMap.put('\u30A8', "\uFF74");
-        sHalfWidthMap.put('\u30A9', "\uFF6B");
-        sHalfWidthMap.put('\u30AA', "\uFF75");
-        sHalfWidthMap.put('\u30AB', "\uFF76");
-        sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
-        sHalfWidthMap.put('\u30AD', "\uFF77");
-        sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
-        sHalfWidthMap.put('\u30AF', "\uFF78");
-        sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
-        sHalfWidthMap.put('\u30B1', "\uFF79");
-        sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
-        sHalfWidthMap.put('\u30B3', "\uFF7A");
-        sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
-        sHalfWidthMap.put('\u30B5', "\uFF7B");
-        sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
-        sHalfWidthMap.put('\u30B7', "\uFF7C");
-        sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
-        sHalfWidthMap.put('\u30B9', "\uFF7D");
-        sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
-        sHalfWidthMap.put('\u30BB', "\uFF7E");
-        sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
-        sHalfWidthMap.put('\u30BD', "\uFF7F");
-        sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
-        sHalfWidthMap.put('\u30BF', "\uFF80");
-        sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
-        sHalfWidthMap.put('\u30C1', "\uFF81");
-        sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
-        sHalfWidthMap.put('\u30C3', "\uFF6F");
-        sHalfWidthMap.put('\u30C4', "\uFF82");
-        sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
-        sHalfWidthMap.put('\u30C6', "\uFF83");
-        sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
-        sHalfWidthMap.put('\u30C8', "\uFF84");
-        sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
-        sHalfWidthMap.put('\u30CA', "\uFF85");
-        sHalfWidthMap.put('\u30CB', "\uFF86");
-        sHalfWidthMap.put('\u30CC', "\uFF87");
-        sHalfWidthMap.put('\u30CD', "\uFF88");
-        sHalfWidthMap.put('\u30CE', "\uFF89");
-        sHalfWidthMap.put('\u30CF', "\uFF8A");
-        sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
-        sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
-        sHalfWidthMap.put('\u30D2', "\uFF8B");
-        sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
-        sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
-        sHalfWidthMap.put('\u30D5', "\uFF8C");
-        sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
-        sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
-        sHalfWidthMap.put('\u30D8', "\uFF8D");
-        sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
-        sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
-        sHalfWidthMap.put('\u30DB', "\uFF8E");
-        sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
-        sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
-        sHalfWidthMap.put('\u30DE', "\uFF8F");
-        sHalfWidthMap.put('\u30DF', "\uFF90");
-        sHalfWidthMap.put('\u30E0', "\uFF91");
-        sHalfWidthMap.put('\u30E1', "\uFF92");
-        sHalfWidthMap.put('\u30E2', "\uFF93");
-        sHalfWidthMap.put('\u30E3', "\uFF6C");
-        sHalfWidthMap.put('\u30E4', "\uFF94");
-        sHalfWidthMap.put('\u30E5', "\uFF6D");
-        sHalfWidthMap.put('\u30E6', "\uFF95");
-        sHalfWidthMap.put('\u30E7', "\uFF6E");
-        sHalfWidthMap.put('\u30E8', "\uFF96");
-        sHalfWidthMap.put('\u30E9', "\uFF97");
-        sHalfWidthMap.put('\u30EA', "\uFF98");
-        sHalfWidthMap.put('\u30EB', "\uFF99");
-        sHalfWidthMap.put('\u30EC', "\uFF9A");
-        sHalfWidthMap.put('\u30ED', "\uFF9B");
-        sHalfWidthMap.put('\u30EE', "\uFF9C");
-        sHalfWidthMap.put('\u30EF', "\uFF9C");
-        sHalfWidthMap.put('\u30F0', "\uFF72");
-        sHalfWidthMap.put('\u30F1', "\uFF74");
-        sHalfWidthMap.put('\u30F2', "\uFF66");
-        sHalfWidthMap.put('\u30F3', "\uFF9D");
-        sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
-        sHalfWidthMap.put('\u30F5', "\uFF76");
-        sHalfWidthMap.put('\u30F6', "\uFF79");
-        sHalfWidthMap.put('\u30FB', "\uFF65");
-        sHalfWidthMap.put('\u30FC', "\uFF70");
-        sHalfWidthMap.put('\uFF01', "!");
-        sHalfWidthMap.put('\uFF02', "\"");
-        sHalfWidthMap.put('\uFF03', "#");
-        sHalfWidthMap.put('\uFF04', "$");
-        sHalfWidthMap.put('\uFF05', "%");
-        sHalfWidthMap.put('\uFF06', "&");
-        sHalfWidthMap.put('\uFF07', "'");
-        sHalfWidthMap.put('\uFF08', "(");
-        sHalfWidthMap.put('\uFF09', ")");
-        sHalfWidthMap.put('\uFF0A', "*");
-        sHalfWidthMap.put('\uFF0B', "+");
-        sHalfWidthMap.put('\uFF0C', ",");
-        sHalfWidthMap.put('\uFF0D', "-");
-        sHalfWidthMap.put('\uFF0E', ".");
-        sHalfWidthMap.put('\uFF0F', "/");
-        sHalfWidthMap.put('\uFF10', "0");
-        sHalfWidthMap.put('\uFF11', "1");
-        sHalfWidthMap.put('\uFF12', "2");
-        sHalfWidthMap.put('\uFF13', "3");
-        sHalfWidthMap.put('\uFF14', "4");
-        sHalfWidthMap.put('\uFF15', "5");
-        sHalfWidthMap.put('\uFF16', "6");
-        sHalfWidthMap.put('\uFF17', "7");
-        sHalfWidthMap.put('\uFF18', "8");
-        sHalfWidthMap.put('\uFF19', "9");
-        sHalfWidthMap.put('\uFF1A', ":");
-        sHalfWidthMap.put('\uFF1B', ";");
-        sHalfWidthMap.put('\uFF1C', "<");
-        sHalfWidthMap.put('\uFF1D', "=");
-        sHalfWidthMap.put('\uFF1E', ">");
-        sHalfWidthMap.put('\uFF1F', "?");
-        sHalfWidthMap.put('\uFF20', "@");
-        sHalfWidthMap.put('\uFF21', "A");
-        sHalfWidthMap.put('\uFF22', "B");
-        sHalfWidthMap.put('\uFF23', "C");
-        sHalfWidthMap.put('\uFF24', "D");
-        sHalfWidthMap.put('\uFF25', "E");
-        sHalfWidthMap.put('\uFF26', "F");
-        sHalfWidthMap.put('\uFF27', "G");
-        sHalfWidthMap.put('\uFF28', "H");
-        sHalfWidthMap.put('\uFF29', "I");
-        sHalfWidthMap.put('\uFF2A', "J");
-        sHalfWidthMap.put('\uFF2B', "K");
-        sHalfWidthMap.put('\uFF2C', "L");
-        sHalfWidthMap.put('\uFF2D', "M");
-        sHalfWidthMap.put('\uFF2E', "N");
-        sHalfWidthMap.put('\uFF2F', "O");
-        sHalfWidthMap.put('\uFF30', "P");
-        sHalfWidthMap.put('\uFF31', "Q");
-        sHalfWidthMap.put('\uFF32', "R");
-        sHalfWidthMap.put('\uFF33', "S");
-        sHalfWidthMap.put('\uFF34', "T");
-        sHalfWidthMap.put('\uFF35', "U");
-        sHalfWidthMap.put('\uFF36', "V");
-        sHalfWidthMap.put('\uFF37', "W");
-        sHalfWidthMap.put('\uFF38', "X");
-        sHalfWidthMap.put('\uFF39', "Y");
-        sHalfWidthMap.put('\uFF3A', "Z");
-        sHalfWidthMap.put('\uFF3B', "[");
-        sHalfWidthMap.put('\uFF3C', "\\");
-        sHalfWidthMap.put('\uFF3D', "]");
-        sHalfWidthMap.put('\uFF3E', "^");
-        sHalfWidthMap.put('\uFF3F', "_");
-        sHalfWidthMap.put('\uFF41', "a");
-        sHalfWidthMap.put('\uFF42', "b");
-        sHalfWidthMap.put('\uFF43', "c");
-        sHalfWidthMap.put('\uFF44', "d");
-        sHalfWidthMap.put('\uFF45', "e");
-        sHalfWidthMap.put('\uFF46', "f");
-        sHalfWidthMap.put('\uFF47', "g");
-        sHalfWidthMap.put('\uFF48', "h");
-        sHalfWidthMap.put('\uFF49', "i");
-        sHalfWidthMap.put('\uFF4A', "j");
-        sHalfWidthMap.put('\uFF4B', "k");
-        sHalfWidthMap.put('\uFF4C', "l");
-        sHalfWidthMap.put('\uFF4D', "m");
-        sHalfWidthMap.put('\uFF4E', "n");
-        sHalfWidthMap.put('\uFF4F', "o");
-        sHalfWidthMap.put('\uFF50', "p");
-        sHalfWidthMap.put('\uFF51', "q");
-        sHalfWidthMap.put('\uFF52', "r");
-        sHalfWidthMap.put('\uFF53', "s");
-        sHalfWidthMap.put('\uFF54', "t");
-        sHalfWidthMap.put('\uFF55', "u");
-        sHalfWidthMap.put('\uFF56', "v");
-        sHalfWidthMap.put('\uFF57', "w");
-        sHalfWidthMap.put('\uFF58', "x");
-        sHalfWidthMap.put('\uFF59', "y");
-        sHalfWidthMap.put('\uFF5A', "z");
-        sHalfWidthMap.put('\uFF5B', "{");
-        sHalfWidthMap.put('\uFF5C', "|");
-        sHalfWidthMap.put('\uFF5D', "}");
-        sHalfWidthMap.put('\uFF5E', "~");
-        sHalfWidthMap.put('\uFF61', "\uFF61");
-        sHalfWidthMap.put('\uFF62', "\uFF62");
-        sHalfWidthMap.put('\uFF63', "\uFF63");
-        sHalfWidthMap.put('\uFF64', "\uFF64");
-        sHalfWidthMap.put('\uFF65', "\uFF65");
-        sHalfWidthMap.put('\uFF66', "\uFF66");
-        sHalfWidthMap.put('\uFF67', "\uFF67");
-        sHalfWidthMap.put('\uFF68', "\uFF68");
-        sHalfWidthMap.put('\uFF69', "\uFF69");
-        sHalfWidthMap.put('\uFF6A', "\uFF6A");
-        sHalfWidthMap.put('\uFF6B', "\uFF6B");
-        sHalfWidthMap.put('\uFF6C', "\uFF6C");
-        sHalfWidthMap.put('\uFF6D', "\uFF6D");
-        sHalfWidthMap.put('\uFF6E', "\uFF6E");
-        sHalfWidthMap.put('\uFF6F', "\uFF6F");
-        sHalfWidthMap.put('\uFF70', "\uFF70");
-        sHalfWidthMap.put('\uFF71', "\uFF71");
-        sHalfWidthMap.put('\uFF72', "\uFF72");
-        sHalfWidthMap.put('\uFF73', "\uFF73");
-        sHalfWidthMap.put('\uFF74', "\uFF74");
-        sHalfWidthMap.put('\uFF75', "\uFF75");
-        sHalfWidthMap.put('\uFF76', "\uFF76");
-        sHalfWidthMap.put('\uFF77', "\uFF77");
-        sHalfWidthMap.put('\uFF78', "\uFF78");
-        sHalfWidthMap.put('\uFF79', "\uFF79");
-        sHalfWidthMap.put('\uFF7A', "\uFF7A");
-        sHalfWidthMap.put('\uFF7B', "\uFF7B");
-        sHalfWidthMap.put('\uFF7C', "\uFF7C");
-        sHalfWidthMap.put('\uFF7D', "\uFF7D");
-        sHalfWidthMap.put('\uFF7E', "\uFF7E");
-        sHalfWidthMap.put('\uFF7F', "\uFF7F");
-        sHalfWidthMap.put('\uFF80', "\uFF80");
-        sHalfWidthMap.put('\uFF81', "\uFF81");
-        sHalfWidthMap.put('\uFF82', "\uFF82");
-        sHalfWidthMap.put('\uFF83', "\uFF83");
-        sHalfWidthMap.put('\uFF84', "\uFF84");
-        sHalfWidthMap.put('\uFF85', "\uFF85");
-        sHalfWidthMap.put('\uFF86', "\uFF86");
-        sHalfWidthMap.put('\uFF87', "\uFF87");
-        sHalfWidthMap.put('\uFF88', "\uFF88");
-        sHalfWidthMap.put('\uFF89', "\uFF89");
-        sHalfWidthMap.put('\uFF8A', "\uFF8A");
-        sHalfWidthMap.put('\uFF8B', "\uFF8B");
-        sHalfWidthMap.put('\uFF8C', "\uFF8C");
-        sHalfWidthMap.put('\uFF8D', "\uFF8D");
-        sHalfWidthMap.put('\uFF8E', "\uFF8E");
-        sHalfWidthMap.put('\uFF8F', "\uFF8F");
-        sHalfWidthMap.put('\uFF90', "\uFF90");
-        sHalfWidthMap.put('\uFF91', "\uFF91");
-        sHalfWidthMap.put('\uFF92', "\uFF92");
-        sHalfWidthMap.put('\uFF93', "\uFF93");
-        sHalfWidthMap.put('\uFF94', "\uFF94");
-        sHalfWidthMap.put('\uFF95', "\uFF95");
-        sHalfWidthMap.put('\uFF96', "\uFF96");
-        sHalfWidthMap.put('\uFF97', "\uFF97");
-        sHalfWidthMap.put('\uFF98', "\uFF98");
-        sHalfWidthMap.put('\uFF99', "\uFF99");
-        sHalfWidthMap.put('\uFF9A', "\uFF9A");
-        sHalfWidthMap.put('\uFF9B', "\uFF9B");
-        sHalfWidthMap.put('\uFF9C', "\uFF9C");
-        sHalfWidthMap.put('\uFF9D', "\uFF9D");
-        sHalfWidthMap.put('\uFF9E', "\uFF9E");
-        sHalfWidthMap.put('\uFF9F', "\uFF9F");
-        sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
-    }
-
-    /**
-     * Returns half-width version of that character if possible. Returns null if not possible
-     * @param ch input character
-     * @return CharSequence object if the mapping for ch exists. Return null otherwise.
-     */
-    public static String tryGetHalfWidthText(final char ch) {
-        if (sHalfWidthMap.containsKey(ch)) {
-            return sHalfWidthMap.get(ch);
-        } else {
-            return null;
-        }
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardBuilder.java b/vcard/java/com/android/vcard/VCardBuilder.java
deleted file mode 100644
index 6ef9ada..0000000
--- a/vcard/java/com/android/vcard/VCardBuilder.java
+++ /dev/null
@@ -1,1996 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * <p>
- * The class which lets users create their own vCard String. Typical usage is as follows:
- * </p>
- * <pre class="prettyprint">final VCardBuilder builder = new VCardBuilder(vcardType);
- * builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
- *     .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
- *     .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
- *     .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
- *     .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
- *     .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
- *     .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE))
- *     .appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE))
- *     .appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
- *     .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
- *     .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
- *     .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
- * return builder.toString();</pre>
- */
-public class VCardBuilder {
-    private static final String LOG_TAG = "VCardBuilder";
-
-    // If you add the other element, please check all the columns are able to be
-    // converted to String.
-    //
-    // e.g. BLOB is not what we can handle here now.
-    private static final Set<String> sAllowedAndroidPropertySet =
-            Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
-                    Nickname.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
-                    Relation.CONTENT_ITEM_TYPE)));
-
-    public static final int DEFAULT_PHONE_TYPE = Phone.TYPE_HOME;
-    public static final int DEFAULT_POSTAL_TYPE = StructuredPostal.TYPE_HOME;
-    public static final int DEFAULT_EMAIL_TYPE = Email.TYPE_OTHER;
-
-    private static final String VCARD_DATA_VCARD = "VCARD";
-    private static final String VCARD_DATA_PUBLIC = "PUBLIC";
-
-    private static final String VCARD_PARAM_SEPARATOR = ";";
-    private static final String VCARD_END_OF_LINE = "\r\n";
-    private static final String VCARD_DATA_SEPARATOR = ":";
-    private static final String VCARD_ITEM_SEPARATOR = ";";
-    private static final String VCARD_WS = " ";
-    private static final String VCARD_PARAM_EQUAL = "=";
-
-    private static final String VCARD_PARAM_ENCODING_QP =
-            "ENCODING=" + VCardConstants.PARAM_ENCODING_QP;
-    private static final String VCARD_PARAM_ENCODING_BASE64_V21 =
-            "ENCODING=" + VCardConstants.PARAM_ENCODING_BASE64;
-    private static final String VCARD_PARAM_ENCODING_BASE64_V30 =
-            "ENCODING=" + VCardConstants.PARAM_ENCODING_B;
-
-    private static final String SHIFT_JIS = "SHIFT_JIS";
-
-    private final int mVCardType;
-
-    private final boolean mIsV30;
-    private final boolean mIsJapaneseMobilePhone;
-    private final boolean mOnlyOneNoteFieldIsAvailable;
-    private final boolean mIsDoCoMo;
-    private final boolean mShouldUseQuotedPrintable;
-    private final boolean mUsesAndroidProperty;
-    private final boolean mUsesDefactProperty;
-    private final boolean mAppendTypeParamName;
-    private final boolean mRefrainsQPToNameProperties;
-    private final boolean mNeedsToConvertPhoneticString;
-
-    private final boolean mShouldAppendCharsetParam;
-
-    private final String mCharset;
-    private final String mVCardCharsetParameter;
-
-    private StringBuilder mBuilder;
-    private boolean mEndAppended;
-
-    public VCardBuilder(final int vcardType) {
-        // Default charset should be used
-        this(vcardType, null);
-    }
-
-    /**
-     * @param vcardType
-     * @param charset If null, we use default charset for export.
-     */
-    public VCardBuilder(final int vcardType, String charset) {
-        mVCardType = vcardType;
-
-        mIsV30 = VCardConfig.isV30(vcardType);
-        mShouldUseQuotedPrintable = VCardConfig.shouldUseQuotedPrintable(vcardType);
-        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
-        mIsJapaneseMobilePhone = VCardConfig.needsToConvertPhoneticString(vcardType);
-        mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType);
-        mUsesAndroidProperty = VCardConfig.usesAndroidSpecificProperty(vcardType);
-        mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
-        mRefrainsQPToNameProperties = VCardConfig.shouldRefrainQPToNameProperties(vcardType);
-        mAppendTypeParamName = VCardConfig.appendTypeParamName(vcardType);
-        mNeedsToConvertPhoneticString = VCardConfig.needsToConvertPhoneticString(vcardType);
-
-        // vCard 2.1 requires charset.
-        // vCard 3.0 does not allow it but we found some devices use it to determine
-        // the exact charset.
-        // We currently append it only when charset other than UTF_8 is used.
-        mShouldAppendCharsetParam = !(mIsV30 && "UTF-8".equalsIgnoreCase(charset));
-
-        if (VCardConfig.isDoCoMo(vcardType)) {
-            if (!SHIFT_JIS.equalsIgnoreCase(charset)) {
-                Log.w(LOG_TAG,
-                        "The charset \"" + charset + "\" is used while "
-                        + SHIFT_JIS + " is needed to be used.");
-                if (TextUtils.isEmpty(charset)) {
-                    mCharset = SHIFT_JIS;
-                } else {
-                    try {
-                        charset = CharsetUtils.charsetForVendor(charset).name();
-                    } catch (UnsupportedCharsetException e) {
-                        Log.i(LOG_TAG,
-                                "Career-specific \"" + charset + "\" was not found (as usual). "
-                                + "Use it as is.");
-                    }
-                    mCharset = charset;
-                }
-            } else {
-                if (mIsDoCoMo) {
-                    try {
-                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
-                    } catch (UnsupportedCharsetException e) {
-                        Log.e(LOG_TAG,
-                                "DoCoMo-specific SHIFT_JIS was not found. "
-                                + "Use SHIFT_JIS as is.");
-                        charset = SHIFT_JIS;
-                    }
-                } else {
-                    try {
-                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
-                    } catch (UnsupportedCharsetException e) {
-                        Log.e(LOG_TAG,
-                                "Career-specific SHIFT_JIS was not found. "
-                                + "Use SHIFT_JIS as is.");
-                        charset = SHIFT_JIS;
-                    }
-                }
-                mCharset = charset;
-            }
-            mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
-        } else {
-            if (TextUtils.isEmpty(charset)) {
-                Log.i(LOG_TAG,
-                        "Use the charset \"" + VCardConfig.DEFAULT_EXPORT_CHARSET
-                        + "\" for export.");
-                mCharset = VCardConfig.DEFAULT_EXPORT_CHARSET;
-                mVCardCharsetParameter = "CHARSET=" + VCardConfig.DEFAULT_EXPORT_CHARSET;
-            } else {
-                try {
-                    charset = CharsetUtils.charsetForVendor(charset).name();
-                } catch (UnsupportedCharsetException e) {
-                    Log.i(LOG_TAG,
-                            "Career-specific \"" + charset + "\" was not found (as usual). "
-                            + "Use it as is.");
-                }
-                mCharset = charset;
-                mVCardCharsetParameter = "CHARSET=" + charset;
-            }
-        }
-        clear();
-    }
-
-    public void clear() {
-        mBuilder = new StringBuilder();
-        mEndAppended = false;
-        appendLine(VCardConstants.PROPERTY_BEGIN, VCARD_DATA_VCARD);
-        if (mIsV30) {
-            appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V30);
-        } else {
-            appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V21);
-        }
-    }
-
-    private boolean containsNonEmptyName(final ContentValues contentValues) {
-        final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME);
-        final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME);
-        final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME);
-        final String prefix = contentValues.getAsString(StructuredName.PREFIX);
-        final String suffix = contentValues.getAsString(StructuredName.SUFFIX);
-        final String phoneticFamilyName =
-                contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
-        final String phoneticMiddleName =
-                contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
-        final String phoneticGivenName =
-                contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
-        final String displayName = contentValues.getAsString(StructuredName.DISPLAY_NAME);
-        return !(TextUtils.isEmpty(familyName) && TextUtils.isEmpty(middleName) &&
-                TextUtils.isEmpty(givenName) && TextUtils.isEmpty(prefix) &&
-                TextUtils.isEmpty(suffix) && TextUtils.isEmpty(phoneticFamilyName) &&
-                TextUtils.isEmpty(phoneticMiddleName) && TextUtils.isEmpty(phoneticGivenName) &&
-                TextUtils.isEmpty(displayName));
-    }
-
-    private ContentValues getPrimaryContentValue(final List<ContentValues> contentValuesList) {
-        ContentValues primaryContentValues = null;
-        ContentValues subprimaryContentValues = null;
-        for (ContentValues contentValues : contentValuesList) {
-            if (contentValues == null){
-                continue;
-            }
-            Integer isSuperPrimary = contentValues.getAsInteger(StructuredName.IS_SUPER_PRIMARY);
-            if (isSuperPrimary != null && isSuperPrimary > 0) {
-                // We choose "super primary" ContentValues.
-                primaryContentValues = contentValues;
-                break;
-            } else if (primaryContentValues == null) {
-                // We choose the first "primary" ContentValues
-                // if "super primary" ContentValues does not exist.
-                final Integer isPrimary = contentValues.getAsInteger(StructuredName.IS_PRIMARY);
-                if (isPrimary != null && isPrimary > 0 &&
-                        containsNonEmptyName(contentValues)) {
-                    primaryContentValues = contentValues;
-                    // Do not break, since there may be ContentValues with "super primary"
-                    // afterword.
-                } else if (subprimaryContentValues == null &&
-                        containsNonEmptyName(contentValues)) {
-                    subprimaryContentValues = contentValues;
-                }
-            }
-        }
-
-        if (primaryContentValues == null) {
-            if (subprimaryContentValues != null) {
-                // We choose the first ContentValues if any "primary" ContentValues does not exist.
-                primaryContentValues = subprimaryContentValues;
-            } else {
-                Log.e(LOG_TAG, "All ContentValues given from database is empty.");
-                primaryContentValues = new ContentValues();
-            }
-        }
-
-        return primaryContentValues;
-    }
-
-    /**
-     * For safety, we'll emit just one value around StructuredName, as external importers
-     * may get confused with multiple "N", "FN", etc. properties, though it is valid in
-     * vCard spec.
-     */
-    public VCardBuilder appendNameProperties(final List<ContentValues> contentValuesList) {
-        if (contentValuesList == null || contentValuesList.isEmpty()) {
-            if (mIsDoCoMo) {
-                appendLine(VCardConstants.PROPERTY_N, "");
-            } else if (mIsV30) {
-                // vCard 3.0 requires "N" and "FN" properties.
-                appendLine(VCardConstants.PROPERTY_N, "");
-                appendLine(VCardConstants.PROPERTY_FN, "");
-            }
-            return this;
-        }
-
-        final ContentValues contentValues = getPrimaryContentValue(contentValuesList);
-        final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME);
-        final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME);
-        final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME);
-        final String prefix = contentValues.getAsString(StructuredName.PREFIX);
-        final String suffix = contentValues.getAsString(StructuredName.SUFFIX);
-        final String displayName = contentValues.getAsString(StructuredName.DISPLAY_NAME);
-
-        if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
-            final boolean reallyAppendCharsetParameterToName =
-                    shouldAppendCharsetParam(familyName, givenName, middleName, prefix, suffix);
-            final boolean reallyUseQuotedPrintableToName =
-                    (!mRefrainsQPToNameProperties &&
-                            !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) &&
-                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) &&
-                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) &&
-                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(prefix) &&
-                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(suffix)));
-
-            final String formattedName;
-            if (!TextUtils.isEmpty(displayName)) {
-                formattedName = displayName;
-            } else {
-                formattedName = VCardUtils.constructNameFromElements(
-                        VCardConfig.getNameOrderType(mVCardType),
-                        familyName, middleName, givenName, prefix, suffix);
-            }
-            final boolean reallyAppendCharsetParameterToFN =
-                    shouldAppendCharsetParam(formattedName);
-            final boolean reallyUseQuotedPrintableToFN =
-                    !mRefrainsQPToNameProperties &&
-                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedName);
-
-            final String encodedFamily;
-            final String encodedGiven;
-            final String encodedMiddle;
-            final String encodedPrefix;
-            final String encodedSuffix;
-            if (reallyUseQuotedPrintableToName) {
-                encodedFamily = encodeQuotedPrintable(familyName);
-                encodedGiven = encodeQuotedPrintable(givenName);
-                encodedMiddle = encodeQuotedPrintable(middleName);
-                encodedPrefix = encodeQuotedPrintable(prefix);
-                encodedSuffix = encodeQuotedPrintable(suffix);
-            } else {
-                encodedFamily = escapeCharacters(familyName);
-                encodedGiven = escapeCharacters(givenName);
-                encodedMiddle = escapeCharacters(middleName);
-                encodedPrefix = escapeCharacters(prefix);
-                encodedSuffix = escapeCharacters(suffix);
-            }
-
-            final String encodedFormattedname =
-                    (reallyUseQuotedPrintableToFN ?
-                            encodeQuotedPrintable(formattedName) : escapeCharacters(formattedName));
-
-            mBuilder.append(VCardConstants.PROPERTY_N);
-            if (mIsDoCoMo) {
-                if (reallyAppendCharsetParameterToName) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(mVCardCharsetParameter);
-                }
-                if (reallyUseQuotedPrintableToName) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(VCARD_PARAM_ENCODING_QP);
-                }
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                // DoCoMo phones require that all the elements in the "family name" field.
-                mBuilder.append(formattedName);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-            } else {
-                if (reallyAppendCharsetParameterToName) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(mVCardCharsetParameter);
-                }
-                if (reallyUseQuotedPrintableToName) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(VCARD_PARAM_ENCODING_QP);
-                }
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                mBuilder.append(encodedFamily);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(encodedGiven);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(encodedMiddle);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(encodedPrefix);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(encodedSuffix);
-            }
-            mBuilder.append(VCARD_END_OF_LINE);
-
-            // FN property
-            mBuilder.append(VCardConstants.PROPERTY_FN);
-            if (reallyAppendCharsetParameterToFN) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(mVCardCharsetParameter);
-            }
-            if (reallyUseQuotedPrintableToFN) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(VCARD_PARAM_ENCODING_QP);
-            }
-            mBuilder.append(VCARD_DATA_SEPARATOR);
-            mBuilder.append(encodedFormattedname);
-            mBuilder.append(VCARD_END_OF_LINE);
-        } else if (!TextUtils.isEmpty(displayName)) {
-            final boolean reallyUseQuotedPrintableToDisplayName =
-                (!mRefrainsQPToNameProperties &&
-                        !VCardUtils.containsOnlyNonCrLfPrintableAscii(displayName));
-            final String encodedDisplayName =
-                    reallyUseQuotedPrintableToDisplayName ?
-                            encodeQuotedPrintable(displayName) :
-                                escapeCharacters(displayName);
-
-            mBuilder.append(VCardConstants.PROPERTY_N);
-            if (shouldAppendCharsetParam(displayName)) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(mVCardCharsetParameter);
-            }
-            if (reallyUseQuotedPrintableToDisplayName) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(VCARD_PARAM_ENCODING_QP);
-            }
-            mBuilder.append(VCARD_DATA_SEPARATOR);
-            mBuilder.append(encodedDisplayName);
-            mBuilder.append(VCARD_ITEM_SEPARATOR);
-            mBuilder.append(VCARD_ITEM_SEPARATOR);
-            mBuilder.append(VCARD_ITEM_SEPARATOR);
-            mBuilder.append(VCARD_ITEM_SEPARATOR);
-            mBuilder.append(VCARD_END_OF_LINE);
-            mBuilder.append(VCardConstants.PROPERTY_FN);
-
-            // Note: "CHARSET" param is not allowed in vCard 3.0, but we may add it
-            //       when it would be useful or necessary for external importers,
-            //       assuming the external importer allows this vioration of the spec.
-            if (shouldAppendCharsetParam(displayName)) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(mVCardCharsetParameter);
-            }
-            mBuilder.append(VCARD_DATA_SEPARATOR);
-            mBuilder.append(encodedDisplayName);
-            mBuilder.append(VCARD_END_OF_LINE);
-        } else if (mIsV30) {
-            // vCard 3.0 specification requires these fields.
-            appendLine(VCardConstants.PROPERTY_N, "");
-            appendLine(VCardConstants.PROPERTY_FN, "");
-        } else if (mIsDoCoMo) {
-            appendLine(VCardConstants.PROPERTY_N, "");
-        }
-
-        appendPhoneticNameFields(contentValues);
-        return this;
-    }
-
-    private void appendPhoneticNameFields(final ContentValues contentValues) {
-        final String phoneticFamilyName;
-        final String phoneticMiddleName;
-        final String phoneticGivenName;
-        {
-            final String tmpPhoneticFamilyName =
-                contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
-            final String tmpPhoneticMiddleName =
-                contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
-            final String tmpPhoneticGivenName =
-                contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
-            if (mNeedsToConvertPhoneticString) {
-                phoneticFamilyName = VCardUtils.toHalfWidthString(tmpPhoneticFamilyName);
-                phoneticMiddleName = VCardUtils.toHalfWidthString(tmpPhoneticMiddleName);
-                phoneticGivenName = VCardUtils.toHalfWidthString(tmpPhoneticGivenName);
-            } else {
-                phoneticFamilyName = tmpPhoneticFamilyName;
-                phoneticMiddleName = tmpPhoneticMiddleName;
-                phoneticGivenName = tmpPhoneticGivenName;
-            }
-        }
-
-        if (TextUtils.isEmpty(phoneticFamilyName)
-                && TextUtils.isEmpty(phoneticMiddleName)
-                && TextUtils.isEmpty(phoneticGivenName)) {
-            if (mIsDoCoMo) {
-                mBuilder.append(VCardConstants.PROPERTY_SOUND);
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N);
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-                mBuilder.append(VCARD_END_OF_LINE);
-            }
-            return;
-        }
-
-        // Try to emit the field(s) related to phonetic name.
-        if (mIsV30) {
-            final String sortString = VCardUtils
-                    .constructNameFromElements(mVCardType,
-                            phoneticFamilyName, phoneticMiddleName, phoneticGivenName);
-            mBuilder.append(VCardConstants.PROPERTY_SORT_STRING);
-            if (shouldAppendCharsetParam(sortString)) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(mVCardCharsetParameter);
-            }
-            mBuilder.append(VCARD_DATA_SEPARATOR);
-            mBuilder.append(escapeCharacters(sortString));
-            mBuilder.append(VCARD_END_OF_LINE);
-        } else if (mIsJapaneseMobilePhone) {
-            // Note: There is no appropriate property for expressing
-            //       phonetic name (Yomigana in Japanese) in vCard 2.1, while there is in
-            //       vCard 3.0 (SORT-STRING).
-            //       We use DoCoMo's way when the device is Japanese one since it is already
-            //       supported by a lot of Japanese mobile phones.
-            //       This is "X-" property, so any parser hopefully would not get
-            //       confused with this.
-            //
-            //       Also, DoCoMo's specification requires vCard composer to use just the first
-            //       column.
-            //       i.e.
-            //       good:  SOUND;X-IRMC-N:Miyakawa Daisuke;;;;
-            //       bad :  SOUND;X-IRMC-N:Miyakawa;Daisuke;;;
-            mBuilder.append(VCardConstants.PROPERTY_SOUND);
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N);
-
-            boolean reallyUseQuotedPrintable =
-                (!mRefrainsQPToNameProperties
-                        && !(VCardUtils.containsOnlyNonCrLfPrintableAscii(
-                                phoneticFamilyName)
-                                && VCardUtils.containsOnlyNonCrLfPrintableAscii(
-                                        phoneticMiddleName)
-                                && VCardUtils.containsOnlyNonCrLfPrintableAscii(
-                                        phoneticGivenName)));
-
-            final String encodedPhoneticFamilyName;
-            final String encodedPhoneticMiddleName;
-            final String encodedPhoneticGivenName;
-            if (reallyUseQuotedPrintable) {
-                encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName);
-                encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName);
-                encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName);
-            } else {
-                encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName);
-                encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName);
-                encodedPhoneticGivenName = escapeCharacters(phoneticGivenName);
-            }
-
-            if (shouldAppendCharsetParam(encodedPhoneticFamilyName,
-                    encodedPhoneticMiddleName, encodedPhoneticGivenName)) {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(mVCardCharsetParameter);
-            }
-            mBuilder.append(VCARD_DATA_SEPARATOR);
-            {
-                boolean first = true;
-                if (!TextUtils.isEmpty(encodedPhoneticFamilyName)) {
-                    mBuilder.append(encodedPhoneticFamilyName);
-                    first = false;
-                }
-                if (!TextUtils.isEmpty(encodedPhoneticMiddleName)) {
-                    if (first) {
-                        first = false;
-                    } else {
-                        mBuilder.append(' ');
-                    }
-                    mBuilder.append(encodedPhoneticMiddleName);
-                }
-                if (!TextUtils.isEmpty(encodedPhoneticGivenName)) {
-                    if (!first) {
-                        mBuilder.append(' ');
-                    }
-                    mBuilder.append(encodedPhoneticGivenName);
-                }
-            }
-            mBuilder.append(VCARD_ITEM_SEPARATOR);  // family;given
-            mBuilder.append(VCARD_ITEM_SEPARATOR);  // given;middle
-            mBuilder.append(VCARD_ITEM_SEPARATOR);  // middle;prefix
-            mBuilder.append(VCARD_ITEM_SEPARATOR);  // prefix;suffix
-            mBuilder.append(VCARD_END_OF_LINE);
-        }
-
-        if (mUsesDefactProperty) {
-            if (!TextUtils.isEmpty(phoneticGivenName)) {
-                final boolean reallyUseQuotedPrintable =
-                    (mShouldUseQuotedPrintable &&
-                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticGivenName));
-                final String encodedPhoneticGivenName;
-                if (reallyUseQuotedPrintable) {
-                    encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName);
-                } else {
-                    encodedPhoneticGivenName = escapeCharacters(phoneticGivenName);
-                }
-                mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_FIRST_NAME);
-                if (shouldAppendCharsetParam(phoneticGivenName)) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(mVCardCharsetParameter);
-                }
-                if (reallyUseQuotedPrintable) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(VCARD_PARAM_ENCODING_QP);
-                }
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                mBuilder.append(encodedPhoneticGivenName);
-                mBuilder.append(VCARD_END_OF_LINE);
-            }  // if (!TextUtils.isEmpty(phoneticGivenName))
-            if (!TextUtils.isEmpty(phoneticMiddleName)) {
-                final boolean reallyUseQuotedPrintable =
-                    (mShouldUseQuotedPrintable &&
-                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticMiddleName));
-                final String encodedPhoneticMiddleName;
-                if (reallyUseQuotedPrintable) {
-                    encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName);
-                } else {
-                    encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName);
-                }
-                mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_MIDDLE_NAME);
-                if (shouldAppendCharsetParam(phoneticMiddleName)) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(mVCardCharsetParameter);
-                }
-                if (reallyUseQuotedPrintable) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(VCARD_PARAM_ENCODING_QP);
-                }
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                mBuilder.append(encodedPhoneticMiddleName);
-                mBuilder.append(VCARD_END_OF_LINE);
-            }  // if (!TextUtils.isEmpty(phoneticGivenName))
-            if (!TextUtils.isEmpty(phoneticFamilyName)) {
-                final boolean reallyUseQuotedPrintable =
-                    (mShouldUseQuotedPrintable &&
-                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticFamilyName));
-                final String encodedPhoneticFamilyName;
-                if (reallyUseQuotedPrintable) {
-                    encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName);
-                } else {
-                    encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName);
-                }
-                mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME);
-                if (shouldAppendCharsetParam(phoneticFamilyName)) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(mVCardCharsetParameter);
-                }
-                if (reallyUseQuotedPrintable) {
-                    mBuilder.append(VCARD_PARAM_SEPARATOR);
-                    mBuilder.append(VCARD_PARAM_ENCODING_QP);
-                }
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                mBuilder.append(encodedPhoneticFamilyName);
-                mBuilder.append(VCARD_END_OF_LINE);
-            }  // if (!TextUtils.isEmpty(phoneticFamilyName))
-        }
-    }
-
-    public VCardBuilder appendNickNames(final List<ContentValues> contentValuesList) {
-        final boolean useAndroidProperty;
-        if (mIsV30) {
-            useAndroidProperty = false;
-        } else if (mUsesAndroidProperty) {
-            useAndroidProperty = true;
-        } else {
-            // There's no way to add this field.
-            return this;
-        }
-        if (contentValuesList != null) {
-            for (ContentValues contentValues : contentValuesList) {
-                final String nickname = contentValues.getAsString(Nickname.NAME);
-                if (TextUtils.isEmpty(nickname)) {
-                    continue;
-                }
-                if (useAndroidProperty) {
-                    appendAndroidSpecificProperty(Nickname.CONTENT_ITEM_TYPE, contentValues);
-                } else {
-                    appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_NICKNAME, nickname);
-                }
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendPhones(final List<ContentValues> contentValuesList) {
-        boolean phoneLineExists = false;
-        if (contentValuesList != null) {
-            Set<String> phoneSet = new HashSet<String>();
-            for (ContentValues contentValues : contentValuesList) {
-                final Integer typeAsObject = contentValues.getAsInteger(Phone.TYPE);
-                final String label = contentValues.getAsString(Phone.LABEL);
-                final Integer isPrimaryAsInteger = contentValues.getAsInteger(Phone.IS_PRIMARY);
-                final boolean isPrimary = (isPrimaryAsInteger != null ?
-                        (isPrimaryAsInteger > 0) : false);
-                String phoneNumber = contentValues.getAsString(Phone.NUMBER);
-                if (phoneNumber != null) {
-                    phoneNumber = phoneNumber.trim();
-                }
-                if (TextUtils.isEmpty(phoneNumber)) {
-                    continue;
-                }
-
-                // PAGER number needs unformatted "phone number".
-                final int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE);
-                if (type == Phone.TYPE_PAGER ||
-                        VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
-                    phoneLineExists = true;
-                    if (!phoneSet.contains(phoneNumber)) {
-                        phoneSet.add(phoneNumber);
-                        appendTelLine(type, label, phoneNumber, isPrimary);
-                    }
-                } else {
-                    final List<String> phoneNumberList = splitAndTrimPhoneNumbers(phoneNumber);
-                    if (phoneNumberList.isEmpty()) {
-                        continue;
-                    }
-                    phoneLineExists = true;
-                    for (String actualPhoneNumber : phoneNumberList) {
-                        if (!phoneSet.contains(actualPhoneNumber)) {
-                            final int format = VCardUtils.getPhoneNumberFormat(mVCardType);
-                            final String formattedPhoneNumber =
-                                    PhoneNumberUtils.formatNumber(actualPhoneNumber, format);
-                            phoneSet.add(actualPhoneNumber);
-                            appendTelLine(type, label, formattedPhoneNumber, isPrimary);
-                        }
-                    }  // for (String actualPhoneNumber : phoneNumberList) {
-                }
-            }
-        }
-
-        if (!phoneLineExists && mIsDoCoMo) {
-            appendTelLine(Phone.TYPE_HOME, "", "", false);
-        }
-
-        return this;
-    }
-
-    /**
-     * <p>
-     * Splits a given string expressing phone numbers into several strings, and remove
-     * unnecessary characters inside them. The size of a returned list becomes 1 when
-     * no split is needed.
-     * </p>
-     * <p>
-     * The given number "may" have several phone numbers when the contact entry is corrupted
-     * because of its original source.
-     * e.g. "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami)"
-     * </p>
-     * <p>
-     * This kind of "phone numbers" will not be created with Android vCard implementation,
-     * but we may encounter them if the source of the input data has already corrupted
-     * implementation.
-     * </p>
-     * <p>
-     * To handle this case, this method first splits its input into multiple parts
-     * (e.g. "111-222-3333 (Miami)", "444-555-6666 (Broward", and 305653-6796 (Miami)") and
-     * removes unnecessary strings like "(Miami)".
-     * </p>
-     * <p>
-     * Do not call this method when trimming is inappropriate for its receivers.
-     * </p>
-     */
-    private List<String> splitAndTrimPhoneNumbers(final String phoneNumber) {
-        final List<String> phoneList = new ArrayList<String>();
-
-        StringBuilder builder = new StringBuilder();
-        final int length = phoneNumber.length();
-        for (int i = 0; i < length; i++) {
-            final char ch = phoneNumber.charAt(i);
-            if (Character.isDigit(ch) || ch == '+') {
-                builder.append(ch);
-            } else if ((ch == ';' || ch == '\n') && builder.length() > 0) {
-                phoneList.add(builder.toString());
-                builder = new StringBuilder();
-            }
-        }
-        if (builder.length() > 0) {
-            phoneList.add(builder.toString());
-        }
-
-        return phoneList;
-    }
-
-    public VCardBuilder appendEmails(final List<ContentValues> contentValuesList) {
-        boolean emailAddressExists = false;
-        if (contentValuesList != null) {
-            final Set<String> addressSet = new HashSet<String>();
-            for (ContentValues contentValues : contentValuesList) {
-                String emailAddress = contentValues.getAsString(Email.DATA);
-                if (emailAddress != null) {
-                    emailAddress = emailAddress.trim();
-                }
-                if (TextUtils.isEmpty(emailAddress)) {
-                    continue;
-                }
-                Integer typeAsObject = contentValues.getAsInteger(Email.TYPE);
-                final int type = (typeAsObject != null ?
-                        typeAsObject : DEFAULT_EMAIL_TYPE);
-                final String label = contentValues.getAsString(Email.LABEL);
-                Integer isPrimaryAsInteger = contentValues.getAsInteger(Email.IS_PRIMARY);
-                final boolean isPrimary = (isPrimaryAsInteger != null ?
-                        (isPrimaryAsInteger > 0) : false);
-                emailAddressExists = true;
-                if (!addressSet.contains(emailAddress)) {
-                    addressSet.add(emailAddress);
-                    appendEmailLine(type, label, emailAddress, isPrimary);
-                }
-            }
-        }
-
-        if (!emailAddressExists && mIsDoCoMo) {
-            appendEmailLine(Email.TYPE_HOME, "", "", false);
-        }
-
-        return this;
-    }
-
-    public VCardBuilder appendPostals(final List<ContentValues> contentValuesList) {
-        if (contentValuesList == null || contentValuesList.isEmpty()) {
-            if (mIsDoCoMo) {
-                mBuilder.append(VCardConstants.PROPERTY_ADR);
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-                mBuilder.append(VCardConstants.PARAM_TYPE_HOME);
-                mBuilder.append(VCARD_DATA_SEPARATOR);
-                mBuilder.append(VCARD_END_OF_LINE);
-            }
-        } else {
-            if (mIsDoCoMo) {
-                appendPostalsForDoCoMo(contentValuesList);
-            } else {
-                appendPostalsForGeneric(contentValuesList);
-            }
-        }
-
-        return this;
-    }
-
-    private static final Map<Integer, Integer> sPostalTypePriorityMap;
-
-    static {
-        sPostalTypePriorityMap = new HashMap<Integer, Integer>();
-        sPostalTypePriorityMap.put(StructuredPostal.TYPE_HOME, 0);
-        sPostalTypePriorityMap.put(StructuredPostal.TYPE_WORK, 1);
-        sPostalTypePriorityMap.put(StructuredPostal.TYPE_OTHER, 2);
-        sPostalTypePriorityMap.put(StructuredPostal.TYPE_CUSTOM, 3);
-    }
-
-    /**
-     * Tries to append just one line. If there's no appropriate address
-     * information, append an empty line.
-     */
-    private void appendPostalsForDoCoMo(final List<ContentValues> contentValuesList) {
-        int currentPriority = Integer.MAX_VALUE;
-        int currentType = Integer.MAX_VALUE;
-        ContentValues currentContentValues = null;
-        for (final ContentValues contentValues : contentValuesList) {
-            if (contentValues == null) {
-                continue;
-            }
-            final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE);
-            final Integer priorityAsInteger = sPostalTypePriorityMap.get(typeAsInteger);
-            final int priority =
-                    (priorityAsInteger != null ? priorityAsInteger : Integer.MAX_VALUE);
-            if (priority < currentPriority) {
-                currentPriority = priority;
-                currentType = typeAsInteger;
-                currentContentValues = contentValues;
-                if (priority == 0) {
-                    break;
-                }
-            }
-        }
-
-        if (currentContentValues == null) {
-            Log.w(LOG_TAG, "Should not come here. Must have at least one postal data.");
-            return;
-        }
-
-        final String label = currentContentValues.getAsString(StructuredPostal.LABEL);
-        appendPostalLine(currentType, label, currentContentValues, false, true);
-    }
-
-    private void appendPostalsForGeneric(final List<ContentValues> contentValuesList) {
-        for (final ContentValues contentValues : contentValuesList) {
-            if (contentValues == null) {
-                continue;
-            }
-            final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE);
-            final int type = (typeAsInteger != null ?
-                    typeAsInteger : DEFAULT_POSTAL_TYPE);
-            final String label = contentValues.getAsString(StructuredPostal.LABEL);
-            final Integer isPrimaryAsInteger =
-                contentValues.getAsInteger(StructuredPostal.IS_PRIMARY);
-            final boolean isPrimary = (isPrimaryAsInteger != null ?
-                    (isPrimaryAsInteger > 0) : false);
-            appendPostalLine(type, label, contentValues, isPrimary, false);
-        }
-    }
-
-    private static class PostalStruct {
-        final boolean reallyUseQuotedPrintable;
-        final boolean appendCharset;
-        final String addressData;
-        public PostalStruct(final boolean reallyUseQuotedPrintable,
-                final boolean appendCharset, final String addressData) {
-            this.reallyUseQuotedPrintable = reallyUseQuotedPrintable;
-            this.appendCharset = appendCharset;
-            this.addressData = addressData;
-        }
-    }
-
-    /**
-     * @return null when there's no information available to construct the data.
-     */
-    private PostalStruct tryConstructPostalStruct(ContentValues contentValues) {
-        // adr-value    = 0*6(text-value ";") text-value
-        //              ; PO Box, Extended Address, Street, Locality, Region, Postal
-        //              ; Code, Country Name
-        final String rawPoBox = contentValues.getAsString(StructuredPostal.POBOX);
-        final String rawNeighborhood = contentValues.getAsString(StructuredPostal.NEIGHBORHOOD);
-        final String rawStreet = contentValues.getAsString(StructuredPostal.STREET);
-        final String rawLocality = contentValues.getAsString(StructuredPostal.CITY);
-        final String rawRegion = contentValues.getAsString(StructuredPostal.REGION);
-        final String rawPostalCode = contentValues.getAsString(StructuredPostal.POSTCODE);
-        final String rawCountry = contentValues.getAsString(StructuredPostal.COUNTRY);
-        final String[] rawAddressArray = new String[]{
-                rawPoBox, rawNeighborhood, rawStreet, rawLocality,
-                rawRegion, rawPostalCode, rawCountry};
-        if (!VCardUtils.areAllEmpty(rawAddressArray)) {
-            final boolean reallyUseQuotedPrintable =
-                (mShouldUseQuotedPrintable &&
-                        !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawAddressArray));
-            final boolean appendCharset =
-                !VCardUtils.containsOnlyPrintableAscii(rawAddressArray);
-            final String encodedPoBox;
-            final String encodedStreet;
-            final String encodedLocality;
-            final String encodedRegion;
-            final String encodedPostalCode;
-            final String encodedCountry;
-            final String encodedNeighborhood;
-
-            final String rawLocality2;
-            // This looks inefficient since we encode rawLocality and rawNeighborhood twice,
-            // but this is intentional.
-            //
-            // QP encoding may add line feeds when needed and the result of
-            // - encodeQuotedPrintable(rawLocality + " " + rawNeighborhood)
-            // may be different from
-            // - encodedLocality + " " + encodedNeighborhood.
-            //
-            // We use safer way.
-            if (TextUtils.isEmpty(rawLocality)) {
-                if (TextUtils.isEmpty(rawNeighborhood)) {
-                    rawLocality2 = "";
-                } else {
-                    rawLocality2 = rawNeighborhood;
-                }
-            } else {
-                if (TextUtils.isEmpty(rawNeighborhood)) {
-                    rawLocality2 = rawLocality;
-                } else {
-                    rawLocality2 = rawLocality + " " + rawNeighborhood;
-                }
-            }
-            if (reallyUseQuotedPrintable) {
-                encodedPoBox = encodeQuotedPrintable(rawPoBox);
-                encodedStreet = encodeQuotedPrintable(rawStreet);
-                encodedLocality = encodeQuotedPrintable(rawLocality2);
-                encodedRegion = encodeQuotedPrintable(rawRegion);
-                encodedPostalCode = encodeQuotedPrintable(rawPostalCode);
-                encodedCountry = encodeQuotedPrintable(rawCountry);
-            } else {
-                encodedPoBox = escapeCharacters(rawPoBox);
-                encodedStreet = escapeCharacters(rawStreet);
-                encodedLocality = escapeCharacters(rawLocality2);
-                encodedRegion = escapeCharacters(rawRegion);
-                encodedPostalCode = escapeCharacters(rawPostalCode);
-                encodedCountry = escapeCharacters(rawCountry);
-                encodedNeighborhood = escapeCharacters(rawNeighborhood);
-            }
-            final StringBuilder addressBuilder = new StringBuilder();
-            addressBuilder.append(encodedPoBox);
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // PO BOX ; Extended Address
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Extended Address : Street
-            addressBuilder.append(encodedStreet);
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Street : Locality
-            addressBuilder.append(encodedLocality);
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Locality : Region
-            addressBuilder.append(encodedRegion);
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Region : Postal Code
-            addressBuilder.append(encodedPostalCode);
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Postal Code : Country
-            addressBuilder.append(encodedCountry);
-            return new PostalStruct(
-                    reallyUseQuotedPrintable, appendCharset, addressBuilder.toString());
-        } else {  // VCardUtils.areAllEmpty(rawAddressArray) == true
-            // Try to use FORMATTED_ADDRESS instead.
-            final String rawFormattedAddress =
-                contentValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
-            if (TextUtils.isEmpty(rawFormattedAddress)) {
-                return null;
-            }
-            final boolean reallyUseQuotedPrintable =
-                (mShouldUseQuotedPrintable &&
-                        !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawFormattedAddress));
-            final boolean appendCharset =
-                !VCardUtils.containsOnlyPrintableAscii(rawFormattedAddress);
-            final String encodedFormattedAddress;
-            if (reallyUseQuotedPrintable) {
-                encodedFormattedAddress = encodeQuotedPrintable(rawFormattedAddress);
-            } else {
-                encodedFormattedAddress = escapeCharacters(rawFormattedAddress);
-            }
-
-            // We use the second value ("Extended Address") just because Japanese mobile phones
-            // do so. If the other importer expects the value be in the other field, some flag may
-            // be needed.
-            final StringBuilder addressBuilder = new StringBuilder();
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // PO BOX ; Extended Address
-            addressBuilder.append(encodedFormattedAddress);
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Extended Address : Street
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Street : Locality
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Locality : Region
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Region : Postal Code
-            addressBuilder.append(VCARD_ITEM_SEPARATOR);  // Postal Code : Country
-            return new PostalStruct(
-                    reallyUseQuotedPrintable, appendCharset, addressBuilder.toString());
-        }
-    }
-
-    public VCardBuilder appendIms(final List<ContentValues> contentValuesList) {
-        if (contentValuesList != null) {
-            for (ContentValues contentValues : contentValuesList) {
-                final Integer protocolAsObject = contentValues.getAsInteger(Im.PROTOCOL);
-                if (protocolAsObject == null) {
-                    continue;
-                }
-                final String propertyName = VCardUtils.getPropertyNameForIm(protocolAsObject);
-                if (propertyName == null) {
-                    continue;
-                }
-                String data = contentValues.getAsString(Im.DATA);
-                if (data != null) {
-                    data = data.trim();
-                }
-                if (TextUtils.isEmpty(data)) {
-                    continue;
-                }
-                final String typeAsString;
-                {
-                    final Integer typeAsInteger = contentValues.getAsInteger(Im.TYPE);
-                    switch (typeAsInteger != null ? typeAsInteger : Im.TYPE_OTHER) {
-                        case Im.TYPE_HOME: {
-                            typeAsString = VCardConstants.PARAM_TYPE_HOME;
-                            break;
-                        }
-                        case Im.TYPE_WORK: {
-                            typeAsString = VCardConstants.PARAM_TYPE_WORK;
-                            break;
-                        }
-                        case Im.TYPE_CUSTOM: {
-                            final String label = contentValues.getAsString(Im.LABEL);
-                            typeAsString = (label != null ? "X-" + label : null);
-                            break;
-                        }
-                        case Im.TYPE_OTHER:  // Ignore
-                        default: {
-                            typeAsString = null;
-                            break;
-                        }
-                    }
-                }
-
-                final List<String> parameterList = new ArrayList<String>();
-                if (!TextUtils.isEmpty(typeAsString)) {
-                    parameterList.add(typeAsString);
-                }
-                final Integer isPrimaryAsInteger = contentValues.getAsInteger(Im.IS_PRIMARY);
-                final boolean isPrimary = (isPrimaryAsInteger != null ?
-                        (isPrimaryAsInteger > 0) : false);
-                if (isPrimary) {
-                    parameterList.add(VCardConstants.PARAM_TYPE_PREF);
-                }
-
-                appendLineWithCharsetAndQPDetection(propertyName, parameterList, data);
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendWebsites(final List<ContentValues> contentValuesList) {
-        if (contentValuesList != null) {
-            for (ContentValues contentValues : contentValuesList) {
-                String website = contentValues.getAsString(Website.URL);
-                if (website != null) {
-                    website = website.trim();
-                }
-
-                // Note: vCard 3.0 does not allow any parameter addition toward "URL"
-                //       property, while there's no document in vCard 2.1.
-                if (!TextUtils.isEmpty(website)) {
-                    appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_URL, website);
-                }
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendOrganizations(final List<ContentValues> contentValuesList) {
-        if (contentValuesList != null) {
-            for (ContentValues contentValues : contentValuesList) {
-                String company = contentValues.getAsString(Organization.COMPANY);
-                if (company != null) {
-                    company = company.trim();
-                }
-                String department = contentValues.getAsString(Organization.DEPARTMENT);
-                if (department != null) {
-                    department = department.trim();
-                }
-                String title = contentValues.getAsString(Organization.TITLE);
-                if (title != null) {
-                    title = title.trim();
-                }
-
-                StringBuilder orgBuilder = new StringBuilder();
-                if (!TextUtils.isEmpty(company)) {
-                    orgBuilder.append(company);
-                }
-                if (!TextUtils.isEmpty(department)) {
-                    if (orgBuilder.length() > 0) {
-                        orgBuilder.append(';');
-                    }
-                    orgBuilder.append(department);
-                }
-                final String orgline = orgBuilder.toString();
-                appendLine(VCardConstants.PROPERTY_ORG, orgline,
-                        !VCardUtils.containsOnlyPrintableAscii(orgline),
-                        (mShouldUseQuotedPrintable &&
-                                !VCardUtils.containsOnlyNonCrLfPrintableAscii(orgline)));
-
-                if (!TextUtils.isEmpty(title)) {
-                    appendLine(VCardConstants.PROPERTY_TITLE, title,
-                            !VCardUtils.containsOnlyPrintableAscii(title),
-                            (mShouldUseQuotedPrintable &&
-                                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(title)));
-                }
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendPhotos(final List<ContentValues> contentValuesList) {
-        if (contentValuesList != null) {
-            for (ContentValues contentValues : contentValuesList) {
-                if (contentValues == null) {
-                    continue;
-                }
-                byte[] data = contentValues.getAsByteArray(Photo.PHOTO);
-                if (data == null) {
-                    continue;
-                }
-                final String photoType = VCardUtils.guessImageType(data);
-                if (photoType == null) {
-                    Log.d(LOG_TAG, "Unknown photo type. Ignored.");
-                    continue;
-                }
-                // TODO: check this works fine.
-                final String photoString = new String(Base64.encode(data, Base64.NO_WRAP));
-                if (!TextUtils.isEmpty(photoString)) {
-                    appendPhotoLine(photoString, photoType);
-                }
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendNotes(final List<ContentValues> contentValuesList) {
-        if (contentValuesList != null) {
-            if (mOnlyOneNoteFieldIsAvailable) {
-                final StringBuilder noteBuilder = new StringBuilder();
-                boolean first = true;
-                for (final ContentValues contentValues : contentValuesList) {
-                    String note = contentValues.getAsString(Note.NOTE);
-                    if (note == null) {
-                        note = "";
-                    }
-                    if (note.length() > 0) {
-                        if (first) {
-                            first = false;
-                        } else {
-                            noteBuilder.append('\n');
-                        }
-                        noteBuilder.append(note);
-                    }
-                }
-                final String noteStr = noteBuilder.toString();
-                // This means we scan noteStr completely twice, which is redundant.
-                // But for now, we assume this is not so time-consuming..
-                final boolean shouldAppendCharsetInfo =
-                    !VCardUtils.containsOnlyPrintableAscii(noteStr);
-                final boolean reallyUseQuotedPrintable =
-                        (mShouldUseQuotedPrintable &&
-                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
-                appendLine(VCardConstants.PROPERTY_NOTE, noteStr,
-                        shouldAppendCharsetInfo, reallyUseQuotedPrintable);
-            } else {
-                for (ContentValues contentValues : contentValuesList) {
-                    final String noteStr = contentValues.getAsString(Note.NOTE);
-                    if (!TextUtils.isEmpty(noteStr)) {
-                        final boolean shouldAppendCharsetInfo =
-                                !VCardUtils.containsOnlyPrintableAscii(noteStr);
-                        final boolean reallyUseQuotedPrintable =
-                                (mShouldUseQuotedPrintable &&
-                                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
-                        appendLine(VCardConstants.PROPERTY_NOTE, noteStr,
-                                shouldAppendCharsetInfo, reallyUseQuotedPrintable);
-                    }
-                }
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendEvents(final List<ContentValues> contentValuesList) {
-        // There's possibility where a given object may have more than one birthday, which
-        // is inappropriate. We just build one birthday.
-        if (contentValuesList != null) {
-            String primaryBirthday = null;
-            String secondaryBirthday = null;
-            for (final ContentValues contentValues : contentValuesList) {
-                if (contentValues == null) {
-                    continue;
-                }
-                final Integer eventTypeAsInteger = contentValues.getAsInteger(Event.TYPE);
-                final int eventType;
-                if (eventTypeAsInteger != null) {
-                    eventType = eventTypeAsInteger;
-                } else {
-                    eventType = Event.TYPE_OTHER;
-                }
-                if (eventType == Event.TYPE_BIRTHDAY) {
-                    final String birthdayCandidate = contentValues.getAsString(Event.START_DATE);
-                    if (birthdayCandidate == null) {
-                        continue;
-                    }
-                    final Integer isSuperPrimaryAsInteger =
-                        contentValues.getAsInteger(Event.IS_SUPER_PRIMARY);
-                    final boolean isSuperPrimary = (isSuperPrimaryAsInteger != null ?
-                            (isSuperPrimaryAsInteger > 0) : false);
-                    if (isSuperPrimary) {
-                        // "super primary" birthday should the prefered one.
-                        primaryBirthday = birthdayCandidate;
-                        break;
-                    }
-                    final Integer isPrimaryAsInteger =
-                        contentValues.getAsInteger(Event.IS_PRIMARY);
-                    final boolean isPrimary = (isPrimaryAsInteger != null ?
-                            (isPrimaryAsInteger > 0) : false);
-                    if (isPrimary) {
-                        // We don't break here since "super primary" birthday may exist later.
-                        primaryBirthday = birthdayCandidate;
-                    } else if (secondaryBirthday == null) {
-                        // First entry is set to the "secondary" candidate.
-                        secondaryBirthday = birthdayCandidate;
-                    }
-                } else if (mUsesAndroidProperty) {
-                    // Event types other than Birthday is not supported by vCard.
-                    appendAndroidSpecificProperty(Event.CONTENT_ITEM_TYPE, contentValues);
-                }
-            }
-            if (primaryBirthday != null) {
-                appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_BDAY,
-                        primaryBirthday.trim());
-            } else if (secondaryBirthday != null){
-                appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_BDAY,
-                        secondaryBirthday.trim());
-            }
-        }
-        return this;
-    }
-
-    public VCardBuilder appendRelation(final List<ContentValues> contentValuesList) {
-        if (mUsesAndroidProperty && contentValuesList != null) {
-            for (final ContentValues contentValues : contentValuesList) {
-                if (contentValues == null) {
-                    continue;
-                }
-                appendAndroidSpecificProperty(Relation.CONTENT_ITEM_TYPE, contentValues);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * @param emitEveryTime If true, builder builds the line even when there's no entry.
-     */
-    public void appendPostalLine(final int type, final String label,
-            final ContentValues contentValues,
-            final boolean isPrimary, final boolean emitEveryTime) {
-        final boolean reallyUseQuotedPrintable;
-        final boolean appendCharset;
-        final String addressValue;
-        {
-            PostalStruct postalStruct = tryConstructPostalStruct(contentValues);
-            if (postalStruct == null) {
-                if (emitEveryTime) {
-                    reallyUseQuotedPrintable = false;
-                    appendCharset = false;
-                    addressValue = "";
-                } else {
-                    return;
-                }
-            } else {
-                reallyUseQuotedPrintable = postalStruct.reallyUseQuotedPrintable;
-                appendCharset = postalStruct.appendCharset;
-                addressValue = postalStruct.addressData;
-            }
-        }
-
-        List<String> parameterList = new ArrayList<String>();
-        if (isPrimary) {
-            parameterList.add(VCardConstants.PARAM_TYPE_PREF);
-        }
-        switch (type) {
-            case StructuredPostal.TYPE_HOME: {
-                parameterList.add(VCardConstants.PARAM_TYPE_HOME);
-                break;
-            }
-            case StructuredPostal.TYPE_WORK: {
-                parameterList.add(VCardConstants.PARAM_TYPE_WORK);
-                break;
-            }
-            case StructuredPostal.TYPE_CUSTOM: {
-                if (!TextUtils.isEmpty(label)
-                        && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
-                    // We're not sure whether the label is valid in the spec
-                    // ("IANA-token" in the vCard 3.0 is unclear...)
-                    // Just  for safety, we add "X-" at the beggining of each label.
-                    // Also checks the label obeys with vCard 3.0 spec.
-                    parameterList.add("X-" + label);
-                }
-                break;
-            }
-            case StructuredPostal.TYPE_OTHER: {
-                break;
-            }
-            default: {
-                Log.e(LOG_TAG, "Unknown StructuredPostal type: " + type);
-                break;
-            }
-        }
-
-        mBuilder.append(VCardConstants.PROPERTY_ADR);
-        if (!parameterList.isEmpty()) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            appendTypeParameters(parameterList);
-        }
-        if (appendCharset) {
-            // Strictly, vCard 3.0 does not allow exporters to emit charset information,
-            // but we will add it since the information should be useful for importers,
-            //
-            // Assume no parser does not emit error with this parameter in vCard 3.0.
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(mVCardCharsetParameter);
-        }
-        if (reallyUseQuotedPrintable) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(VCARD_PARAM_ENCODING_QP);
-        }
-        mBuilder.append(VCARD_DATA_SEPARATOR);
-        mBuilder.append(addressValue);
-        mBuilder.append(VCARD_END_OF_LINE);
-    }
-
-    public void appendEmailLine(final int type, final String label,
-            final String rawValue, final boolean isPrimary) {
-        final String typeAsString;
-        switch (type) {
-            case Email.TYPE_CUSTOM: {
-                if (VCardUtils.isMobilePhoneLabel(label)) {
-                    typeAsString = VCardConstants.PARAM_TYPE_CELL;
-                } else if (!TextUtils.isEmpty(label)
-                        && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
-                    typeAsString = "X-" + label;
-                } else {
-                    typeAsString = null;
-                }
-                break;
-            }
-            case Email.TYPE_HOME: {
-                typeAsString = VCardConstants.PARAM_TYPE_HOME;
-                break;
-            }
-            case Email.TYPE_WORK: {
-                typeAsString = VCardConstants.PARAM_TYPE_WORK;
-                break;
-            }
-            case Email.TYPE_OTHER: {
-                typeAsString = null;
-                break;
-            }
-            case Email.TYPE_MOBILE: {
-                typeAsString = VCardConstants.PARAM_TYPE_CELL;
-                break;
-            }
-            default: {
-                Log.e(LOG_TAG, "Unknown Email type: " + type);
-                typeAsString = null;
-                break;
-            }
-        }
-
-        final List<String> parameterList = new ArrayList<String>();
-        if (isPrimary) {
-            parameterList.add(VCardConstants.PARAM_TYPE_PREF);
-        }
-        if (!TextUtils.isEmpty(typeAsString)) {
-            parameterList.add(typeAsString);
-        }
-
-        appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_EMAIL, parameterList,
-                rawValue);
-    }
-
-    public void appendTelLine(final Integer typeAsInteger, final String label,
-            final String encodedValue, boolean isPrimary) {
-        mBuilder.append(VCardConstants.PROPERTY_TEL);
-        mBuilder.append(VCARD_PARAM_SEPARATOR);
-
-        final int type;
-        if (typeAsInteger == null) {
-            type = Phone.TYPE_OTHER;
-        } else {
-            type = typeAsInteger;
-        }
-
-        ArrayList<String> parameterList = new ArrayList<String>();
-        switch (type) {
-            case Phone.TYPE_HOME: {
-                parameterList.addAll(
-                        Arrays.asList(VCardConstants.PARAM_TYPE_HOME));
-                break;
-            }
-            case Phone.TYPE_WORK: {
-                parameterList.addAll(
-                        Arrays.asList(VCardConstants.PARAM_TYPE_WORK));
-                break;
-            }
-            case Phone.TYPE_FAX_HOME: {
-                parameterList.addAll(
-                        Arrays.asList(VCardConstants.PARAM_TYPE_HOME, VCardConstants.PARAM_TYPE_FAX));
-                break;
-            }
-            case Phone.TYPE_FAX_WORK: {
-                parameterList.addAll(
-                        Arrays.asList(VCardConstants.PARAM_TYPE_WORK, VCardConstants.PARAM_TYPE_FAX));
-                break;
-            }
-            case Phone.TYPE_MOBILE: {
-                parameterList.add(VCardConstants.PARAM_TYPE_CELL);
-                break;
-            }
-            case Phone.TYPE_PAGER: {
-                if (mIsDoCoMo) {
-                    // Not sure about the reason, but previous implementation had
-                    // used "VOICE" instead of "PAGER"
-                    parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
-                } else {
-                    parameterList.add(VCardConstants.PARAM_TYPE_PAGER);
-                }
-                break;
-            }
-            case Phone.TYPE_OTHER: {
-                parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
-                break;
-            }
-            case Phone.TYPE_CAR: {
-                parameterList.add(VCardConstants.PARAM_TYPE_CAR);
-                break;
-            }
-            case Phone.TYPE_COMPANY_MAIN: {
-                // There's no relevant field in vCard (at least 2.1).
-                parameterList.add(VCardConstants.PARAM_TYPE_WORK);
-                isPrimary = true;
-                break;
-            }
-            case Phone.TYPE_ISDN: {
-                parameterList.add(VCardConstants.PARAM_TYPE_ISDN);
-                break;
-            }
-            case Phone.TYPE_MAIN: {
-                isPrimary = true;
-                break;
-            }
-            case Phone.TYPE_OTHER_FAX: {
-                parameterList.add(VCardConstants.PARAM_TYPE_FAX);
-                break;
-            }
-            case Phone.TYPE_TELEX: {
-                parameterList.add(VCardConstants.PARAM_TYPE_TLX);
-                break;
-            }
-            case Phone.TYPE_WORK_MOBILE: {
-                parameterList.addAll(
-                        Arrays.asList(VCardConstants.PARAM_TYPE_WORK, VCardConstants.PARAM_TYPE_CELL));
-                break;
-            }
-            case Phone.TYPE_WORK_PAGER: {
-                parameterList.add(VCardConstants.PARAM_TYPE_WORK);
-                // See above.
-                if (mIsDoCoMo) {
-                    parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
-                } else {
-                    parameterList.add(VCardConstants.PARAM_TYPE_PAGER);
-                }
-                break;
-            }
-            case Phone.TYPE_MMS: {
-                parameterList.add(VCardConstants.PARAM_TYPE_MSG);
-                break;
-            }
-            case Phone.TYPE_CUSTOM: {
-                if (TextUtils.isEmpty(label)) {
-                    // Just ignore the custom type.
-                    parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
-                } else if (VCardUtils.isMobilePhoneLabel(label)) {
-                    parameterList.add(VCardConstants.PARAM_TYPE_CELL);
-                } else {
-                    final String upperLabel = label.toUpperCase();
-                    if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) {
-                        parameterList.add(upperLabel);
-                    } else if (VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
-                        // Note: Strictly, vCard 2.1 does not allow "X-" parameter without
-                        //       "TYPE=" string.
-                        parameterList.add("X-" + label);
-                    }
-                }
-                break;
-            }
-            case Phone.TYPE_RADIO:
-            case Phone.TYPE_TTY_TDD:
-            default: {
-                break;
-            }
-        }
-
-        if (isPrimary) {
-            parameterList.add(VCardConstants.PARAM_TYPE_PREF);
-        }
-
-        if (parameterList.isEmpty()) {
-            appendUncommonPhoneType(mBuilder, type);
-        } else {
-            appendTypeParameters(parameterList);
-        }
-
-        mBuilder.append(VCARD_DATA_SEPARATOR);
-        mBuilder.append(encodedValue);
-        mBuilder.append(VCARD_END_OF_LINE);
-    }
-
-    /**
-     * Appends phone type string which may not be available in some devices.
-     */
-    private void appendUncommonPhoneType(final StringBuilder builder, final Integer type) {
-        if (mIsDoCoMo) {
-            // The previous implementation for DoCoMo had been conservative
-            // about miscellaneous types.
-            builder.append(VCardConstants.PARAM_TYPE_VOICE);
-        } else {
-            String phoneType = VCardUtils.getPhoneTypeString(type);
-            if (phoneType != null) {
-                appendTypeParameter(phoneType);
-            } else {
-                Log.e(LOG_TAG, "Unknown or unsupported (by vCard) Phone type: " + type);
-            }
-        }
-    }
-
-    /**
-     * @param encodedValue Must be encoded by BASE64 
-     * @param photoType
-     */
-    public void appendPhotoLine(final String encodedValue, final String photoType) {
-        StringBuilder tmpBuilder = new StringBuilder();
-        tmpBuilder.append(VCardConstants.PROPERTY_PHOTO);
-        tmpBuilder.append(VCARD_PARAM_SEPARATOR);
-        if (mIsV30) {
-            tmpBuilder.append(VCARD_PARAM_ENCODING_BASE64_V30);
-        } else {
-            tmpBuilder.append(VCARD_PARAM_ENCODING_BASE64_V21);
-        }
-        tmpBuilder.append(VCARD_PARAM_SEPARATOR);
-        appendTypeParameter(tmpBuilder, photoType);
-        tmpBuilder.append(VCARD_DATA_SEPARATOR);
-        tmpBuilder.append(encodedValue);
-
-        final String tmpStr = tmpBuilder.toString();
-        tmpBuilder = new StringBuilder();
-        int lineCount = 0;
-        final int length = tmpStr.length();
-        final int maxNumForFirstLine = VCardConstants.MAX_CHARACTER_NUMS_BASE64_V30
-                - VCARD_END_OF_LINE.length();
-        final int maxNumInGeneral = maxNumForFirstLine - VCARD_WS.length();
-        int maxNum = maxNumForFirstLine;
-        for (int i = 0; i < length; i++) {
-            tmpBuilder.append(tmpStr.charAt(i));
-            lineCount++;
-            if (lineCount > maxNum) {
-                tmpBuilder.append(VCARD_END_OF_LINE);
-                tmpBuilder.append(VCARD_WS);
-                maxNum = maxNumInGeneral;
-                lineCount = 0;
-            }
-        }
-        mBuilder.append(tmpBuilder.toString());
-        mBuilder.append(VCARD_END_OF_LINE);
-        mBuilder.append(VCARD_END_OF_LINE);
-    }
-
-    public void appendAndroidSpecificProperty(
-            final String mimeType, ContentValues contentValues) {
-        if (!sAllowedAndroidPropertySet.contains(mimeType)) {
-            return;
-        }
-        final List<String> rawValueList = new ArrayList<String>();
-        for (int i = 1; i <= VCardConstants.MAX_DATA_COLUMN; i++) {
-            String value = contentValues.getAsString("data" + i);
-            if (value == null) {
-                value = "";
-            }
-            rawValueList.add(value);
-        }
-
-        boolean needCharset =
-            (mShouldAppendCharsetParam &&
-                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
-        boolean reallyUseQuotedPrintable =
-            (mShouldUseQuotedPrintable &&
-                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
-        mBuilder.append(VCardConstants.PROPERTY_X_ANDROID_CUSTOM);
-        if (needCharset) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(mVCardCharsetParameter);
-        }
-        if (reallyUseQuotedPrintable) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(VCARD_PARAM_ENCODING_QP);
-        }
-        mBuilder.append(VCARD_DATA_SEPARATOR);
-        mBuilder.append(mimeType);  // Should not be encoded.
-        for (String rawValue : rawValueList) {
-            final String encodedValue;
-            if (reallyUseQuotedPrintable) {
-                encodedValue = encodeQuotedPrintable(rawValue);
-            } else {
-                // TODO: one line may be too huge, which may be invalid in vCard 3.0
-                //        (which says "When generating a content line, lines longer than
-                //        75 characters SHOULD be folded"), though several
-                //        (even well-known) applications do not care this.
-                encodedValue = escapeCharacters(rawValue);
-            }
-            mBuilder.append(VCARD_ITEM_SEPARATOR);
-            mBuilder.append(encodedValue);
-        }
-        mBuilder.append(VCARD_END_OF_LINE);
-    }
-
-    public void appendLineWithCharsetAndQPDetection(final String propertyName,
-            final String rawValue) {
-        appendLineWithCharsetAndQPDetection(propertyName, null, rawValue);
-    }
-
-    public void appendLineWithCharsetAndQPDetection(
-            final String propertyName, final List<String> rawValueList) {
-        appendLineWithCharsetAndQPDetection(propertyName, null, rawValueList);
-    }
-
-    public void appendLineWithCharsetAndQPDetection(final String propertyName,
-            final List<String> parameterList, final String rawValue) {
-        final boolean needCharset =
-                !VCardUtils.containsOnlyPrintableAscii(rawValue);
-        final boolean reallyUseQuotedPrintable =
-                (mShouldUseQuotedPrintable &&
-                        !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue));
-        appendLine(propertyName, parameterList,
-                rawValue, needCharset, reallyUseQuotedPrintable);
-    }
-
-    public void appendLineWithCharsetAndQPDetection(final String propertyName,
-            final List<String> parameterList, final List<String> rawValueList) {
-        boolean needCharset =
-            (mShouldAppendCharsetParam &&
-                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
-        boolean reallyUseQuotedPrintable =
-            (mShouldUseQuotedPrintable &&
-                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
-        appendLine(propertyName, parameterList, rawValueList,
-                needCharset, reallyUseQuotedPrintable);
-    }
-
-    /**
-     * Appends one line with a given property name and value.  
-     */
-    public void appendLine(final String propertyName, final String rawValue) {
-        appendLine(propertyName, rawValue, false, false);
-    }
-
-    public void appendLine(final String propertyName, final List<String> rawValueList) {
-        appendLine(propertyName, rawValueList, false, false);
-    }
-
-    public void appendLine(final String propertyName,
-            final String rawValue, final boolean needCharset,
-            boolean reallyUseQuotedPrintable) {
-        appendLine(propertyName, null, rawValue, needCharset, reallyUseQuotedPrintable);
-    }
-
-    public void appendLine(final String propertyName, final List<String> parameterList,
-            final String rawValue) {
-        appendLine(propertyName, parameterList, rawValue, false, false);
-    }
-
-    public void appendLine(final String propertyName, final List<String> parameterList,
-            final String rawValue, final boolean needCharset,
-            boolean reallyUseQuotedPrintable) {
-        mBuilder.append(propertyName);
-        if (parameterList != null && parameterList.size() > 0) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            appendTypeParameters(parameterList);
-        }
-        if (needCharset) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(mVCardCharsetParameter);
-        }
-
-        final String encodedValue;
-        if (reallyUseQuotedPrintable) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(VCARD_PARAM_ENCODING_QP);
-            encodedValue = encodeQuotedPrintable(rawValue);
-        } else {
-            // TODO: one line may be too huge, which may be invalid in vCard spec, though
-            //       several (even well-known) applications do not care that violation.
-            encodedValue = escapeCharacters(rawValue);
-        }
-
-        mBuilder.append(VCARD_DATA_SEPARATOR);
-        mBuilder.append(encodedValue);
-        mBuilder.append(VCARD_END_OF_LINE);
-    }
-
-    public void appendLine(final String propertyName, final List<String> rawValueList,
-            final boolean needCharset, boolean needQuotedPrintable) {
-        appendLine(propertyName, null, rawValueList, needCharset, needQuotedPrintable);
-    }
-
-    public void appendLine(final String propertyName, final List<String> parameterList,
-            final List<String> rawValueList, final boolean needCharset,
-            final boolean needQuotedPrintable) {
-        mBuilder.append(propertyName);
-        if (parameterList != null && parameterList.size() > 0) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            appendTypeParameters(parameterList);
-        }
-        if (needCharset) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(mVCardCharsetParameter);
-        }
-        if (needQuotedPrintable) {
-            mBuilder.append(VCARD_PARAM_SEPARATOR);
-            mBuilder.append(VCARD_PARAM_ENCODING_QP);
-        }
-
-        mBuilder.append(VCARD_DATA_SEPARATOR);
-        boolean first = true;
-        for (String rawValue : rawValueList) {
-            final String encodedValue;
-            if (needQuotedPrintable) {
-                encodedValue = encodeQuotedPrintable(rawValue);
-            } else {
-                // TODO: one line may be too huge, which may be invalid in vCard 3.0
-                //        (which says "When generating a content line, lines longer than
-                //        75 characters SHOULD be folded"), though several
-                //        (even well-known) applications do not care this.
-                encodedValue = escapeCharacters(rawValue);
-            }
-
-            if (first) {
-                first = false;
-            } else {
-                mBuilder.append(VCARD_ITEM_SEPARATOR);
-            }
-            mBuilder.append(encodedValue);
-        }
-        mBuilder.append(VCARD_END_OF_LINE);
-    }
-
-    /**
-     * VCARD_PARAM_SEPARATOR must be appended before this method being called.
-     */
-    private void appendTypeParameters(final List<String> types) {
-        // We may have to make this comma separated form like "TYPE=DOM,WORK" in the future,
-        // which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
-        boolean first = true;
-        for (final String typeValue : types) {
-            // Note: vCard 3.0 specifies the different type of acceptable type Strings, but
-            //       we don't emit that kind of vCard 3.0 specific type since there should be
-            //       high probabilyty in which external importers cannot understand them.
-            //
-            // e.g. TYPE="\u578B\u306B\u3087" (vCard 3.0 allows non-Ascii characters if they
-            //      are quoted.)
-            if (!VCardUtils.isV21Word(typeValue)) {
-                continue;
-            }
-            if (first) {
-                first = false;
-            } else {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-            }
-            appendTypeParameter(typeValue);
-        }
-    }
-
-    /**
-     * VCARD_PARAM_SEPARATOR must be appended before this method being called.
-     */
-    private void appendTypeParameter(final String type) {
-        appendTypeParameter(mBuilder, type);
-    }
-
-    private void appendTypeParameter(final StringBuilder builder, final String type) {
-        // Refrain from using appendType() so that "TYPE=" is not be appended when the
-        // device is DoCoMo's (just for safety).
-        //
-        // Note: In vCard 3.0, Type strings also can be like this: "TYPE=HOME,PREF"
-        if ((mIsV30 || mAppendTypeParamName) && !mIsDoCoMo) {
-            builder.append(VCardConstants.PARAM_TYPE).append(VCARD_PARAM_EQUAL);
-        }
-        builder.append(type);
-    }
-
-    /**
-     * Returns true when the property line should contain charset parameter
-     * information. This method may return true even when vCard version is 3.0.
-     *
-     * Strictly, adding charset information is invalid in VCard 3.0.
-     * However we'll add the info only when charset we use is not UTF-8
-     * in vCard 3.0 format, since parser side may be able to use the charset
-     * via this field, though we may encounter another problem by adding it.
-     *
-     * e.g. Japanese mobile phones use Shift_Jis while RFC 2426
-     * recommends UTF-8. By adding this field, parsers may be able
-     * to know this text is NOT UTF-8 but Shift_Jis.
-     */
-    private boolean shouldAppendCharsetParam(String...propertyValueList) {
-        if (!mShouldAppendCharsetParam) {
-            return false;
-        }
-        for (String propertyValue : propertyValueList) {
-            if (!VCardUtils.containsOnlyPrintableAscii(propertyValue)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String encodeQuotedPrintable(final String str) {
-        if (TextUtils.isEmpty(str)) {
-            return "";
-        }
-
-        final StringBuilder builder = new StringBuilder();
-        int index = 0;
-        int lineCount = 0;
-        byte[] strArray = null;
-
-        try {
-            strArray = str.getBytes(mCharset);
-        } catch (UnsupportedEncodingException e) {
-            Log.e(LOG_TAG, "Charset " + mCharset + " cannot be used. "
-                    + "Try default charset");
-            strArray = str.getBytes();
-        }
-        while (index < strArray.length) {
-            builder.append(String.format("=%02X", strArray[index]));
-            index += 1;
-            lineCount += 3;
-
-            if (lineCount >= 67) {
-                // Specification requires CRLF must be inserted before the
-                // length of the line
-                // becomes more than 76.
-                // Assuming that the next character is a multi-byte character,
-                // it will become
-                // 6 bytes.
-                // 76 - 6 - 3 = 67
-                builder.append("=\r\n");
-                lineCount = 0;
-            }
-        }
-
-        return builder.toString();
-    }
-
-    /**
-     * Append '\' to the characters which should be escaped. The character set is different
-     * not only between vCard 2.1 and vCard 3.0 but also among each device.
-     *
-     * Note that Quoted-Printable string must not be input here.
-     */
-    @SuppressWarnings("fallthrough")
-    private String escapeCharacters(final String unescaped) {
-        if (TextUtils.isEmpty(unescaped)) {
-            return "";
-        }
-
-        final StringBuilder tmpBuilder = new StringBuilder();
-        final int length = unescaped.length();
-        for (int i = 0; i < length; i++) {
-            final char ch = unescaped.charAt(i);
-            switch (ch) {
-                case ';': {
-                    tmpBuilder.append('\\');
-                    tmpBuilder.append(';');
-                    break;
-                }
-                case '\r': {
-                    if (i + 1 < length) {
-                        char nextChar = unescaped.charAt(i);
-                        if (nextChar == '\n') {
-                            break;
-                        } else {
-                            // fall through
-                        }
-                    } else {
-                        // fall through
-                    }
-                }
-                case '\n': {
-                    // In vCard 2.1, there's no specification about this, while
-                    // vCard 3.0 explicitly requires this should be encoded to "\n".
-                    tmpBuilder.append("\\n");
-                    break;
-                }
-                case '\\': {
-                    if (mIsV30) {
-                        tmpBuilder.append("\\\\");
-                        break;
-                    } else {
-                        // fall through
-                    }
-                }
-                case '<':
-                case '>': {
-                    if (mIsDoCoMo) {
-                        tmpBuilder.append('\\');
-                        tmpBuilder.append(ch);
-                    } else {
-                        tmpBuilder.append(ch);
-                    }
-                    break;
-                }
-                case ',': {
-                    if (mIsV30) {
-                        tmpBuilder.append("\\,");
-                    } else {
-                        tmpBuilder.append(ch);
-                    }
-                    break;
-                }
-                default: {
-                    tmpBuilder.append(ch);
-                    break;
-                }
-            }
-        }
-        return tmpBuilder.toString();
-    }
-
-    @Override
-    public String toString() {
-        if (!mEndAppended) {
-            if (mIsDoCoMo) {
-                appendLine(VCardConstants.PROPERTY_X_CLASS, VCARD_DATA_PUBLIC);
-                appendLine(VCardConstants.PROPERTY_X_REDUCTION, "");
-                appendLine(VCardConstants.PROPERTY_X_NO, "");
-                appendLine(VCardConstants.PROPERTY_X_DCM_HMN_MODE, "");
-            }
-            appendLine(VCardConstants.PROPERTY_END, VCARD_DATA_VCARD);
-            mEndAppended = true;
-        }
-        return mBuilder.toString();
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardComposer.java b/vcard/java/com/android/vcard/VCardComposer.java
deleted file mode 100644
index 7038955..0000000
--- a/vcard/java/com/android/vcard/VCardComposer.java
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Entity;
-import android.content.EntityIterator;
-import android.content.Entity.NamedContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.RawContactsEntity;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.text.TextUtils;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import com.android.vcard.exception.VCardException;
-
-import java.io.BufferedWriter;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * <p>
- * The class for composing vCard from Contacts information.
- * </p>
- * <p>
- * Usually, this class should be used like this.
- * </p>
- * <pre class="prettyprint">VCardComposer composer = null;
- * try {
- *     composer = new VCardComposer(context);
- *     composer.addHandler(
- *             composer.new HandlerForOutputStream(outputStream));
- *     if (!composer.init()) {
- *         // Do something handling the situation.
- *         return;
- *     }
- *     while (!composer.isAfterLast()) {
- *         if (mCanceled) {
- *             // Assume a user may cancel this operation during the export.
- *             return;
- *         }
- *         if (!composer.createOneEntry()) {
- *             // Do something handling the error situation.
- *             return;
- *         }
- *     }
- * } finally {
- *     if (composer != null) {
- *         composer.terminate();
- *     }
- * }</pre>
- * <p>
- * Users have to manually take care of memory efficiency. Even one vCard may contain
- * image of non-trivial size for mobile devices.
- * </p>
- * <p>
- * {@link VCardBuilder} is used to build each vCard.
- * </p>
- */
-public class VCardComposer {
-    private static final String LOG_TAG = "VCardComposer";
-
-    public static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
-        "Failed to get database information";
-
-    public static final String FAILURE_REASON_NO_ENTRY =
-        "There's no exportable in the database";
-
-    public static final String FAILURE_REASON_NOT_INITIALIZED =
-        "The vCard composer object is not correctly initialized";
-
-    /** Should be visible only from developers... (no need to translate, hopefully) */
-    public static final String FAILURE_REASON_UNSUPPORTED_URI =
-        "The Uri vCard composer received is not supported by the composer.";
-
-    public static final String NO_ERROR = "No error";
-
-    public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
-
-    // Strictly speaking, "Shift_JIS" is the most appropriate, but we use upper version here,
-    // since usual vCard devices for Japanese devices already use it.
-    private static final String SHIFT_JIS = "SHIFT_JIS";
-    private static final String UTF_8 = "UTF-8";
-
-    /**
-     * Special URI for testing.
-     */
-    public static final String VCARD_TEST_AUTHORITY = "com.android.unit_tests.vcard";
-    public static final Uri VCARD_TEST_AUTHORITY_URI =
-        Uri.parse("content://" + VCARD_TEST_AUTHORITY);
-    public static final Uri CONTACTS_TEST_CONTENT_URI =
-        Uri.withAppendedPath(VCARD_TEST_AUTHORITY_URI, "contacts");
-
-    private static final Map<Integer, String> sImMap;
-
-    static {
-        sImMap = new HashMap<Integer, String>();
-        sImMap.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
-        sImMap.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
-        sImMap.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
-        sImMap.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
-        sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
-        sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
-        // We don't add Google talk here since it has to be handled separately.
-    }
-
-    public static interface OneEntryHandler {
-        public boolean onInit(Context context);
-        public boolean onEntryCreated(String vcard);
-        public void onTerminate();
-    }
-
-    /**
-     * <p>
-     * An useful handler for emitting vCard String to an OutputStream object one by one.
-     * </p>
-     * <p>
-     * The input OutputStream object is closed() on {@link #onTerminate()}.
-     * Must not close the stream outside this class.
-     * </p>
-     */
-    public final class HandlerForOutputStream implements OneEntryHandler {
-        @SuppressWarnings("hiding")
-        private static final String LOG_TAG = "VCardComposer.HandlerForOutputStream";
-
-        private boolean mOnTerminateIsCalled = false;
-
-        private final OutputStream mOutputStream; // mWriter will close this.
-        private Writer mWriter;
-
-        /**
-         * Input stream will be closed on the detruction of this object.
-         */
-        public HandlerForOutputStream(final OutputStream outputStream) {
-            mOutputStream = outputStream;
-        }
-
-        public boolean onInit(final Context context) {
-            try {
-                mWriter = new BufferedWriter(new OutputStreamWriter(
-                        mOutputStream, mCharset));
-            } catch (UnsupportedEncodingException e1) {
-                Log.e(LOG_TAG, "Unsupported charset: " + mCharset);
-                mErrorReason = "Encoding is not supported (usually this does not happen!): "
-                        + mCharset;
-                return false;
-            }
-
-            if (mIsDoCoMo) {
-                try {
-                    // Create one empty entry.
-                    mWriter.write(createOneEntryInternal("-1", null));
-                } catch (VCardException e) {
-                    Log.e(LOG_TAG, "VCardException has been thrown during on Init(): " +
-                            e.getMessage());
-                    return false;
-                } catch (IOException e) {
-                    Log.e(LOG_TAG,
-                            "IOException occurred during exportOneContactData: "
-                                    + e.getMessage());
-                    mErrorReason = "IOException occurred: " + e.getMessage();
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        public boolean onEntryCreated(String vcard) {
-            try {
-                mWriter.write(vcard);
-            } catch (IOException e) {
-                Log.e(LOG_TAG,
-                        "IOException occurred during exportOneContactData: "
-                                + e.getMessage());
-                mErrorReason = "IOException occurred: " + e.getMessage();
-                return false;
-            }
-            return true;
-        }
-
-        public void onTerminate() {
-            mOnTerminateIsCalled = true;
-            if (mWriter != null) {
-                try {
-                    // Flush and sync the data so that a user is able to pull
-                    // the SDCard just after
-                    // the export.
-                    mWriter.flush();
-                    if (mOutputStream != null
-                            && mOutputStream instanceof FileOutputStream) {
-                            ((FileOutputStream) mOutputStream).getFD().sync();
-                    }
-                } catch (IOException e) {
-                    Log.d(LOG_TAG,
-                            "IOException during closing the output stream: "
-                                    + e.getMessage());
-                } finally {
-                    closeOutputStream();
-                }
-            }
-        }
-
-        public void closeOutputStream() {
-            try {
-                mWriter.close();
-            } catch (IOException e) {
-                Log.w(LOG_TAG, "IOException is thrown during close(). Ignoring.");
-            }
-        }
-
-        @Override
-        public void finalize() {
-            if (!mOnTerminateIsCalled) {
-                onTerminate();
-            }
-        }
-    }
-
-    private final Context mContext;
-    private final int mVCardType;
-    private final boolean mCareHandlerErrors;
-    private final ContentResolver mContentResolver;
-
-    private final boolean mIsDoCoMo;
-    private Cursor mCursor;
-    private int mIdColumn;
-
-    private final String mCharset;
-    private boolean mTerminateIsCalled;
-    private final List<OneEntryHandler> mHandlerList;
-
-    private String mErrorReason = NO_ERROR;
-
-    private static final String[] sContactsProjection = new String[] {
-        Contacts._ID,
-    };
-
-    public VCardComposer(Context context) {
-        this(context, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
-    }
-
-    /**
-     * The variant which sets charset to null and sets careHandlerErrors to true.
-     */
-    public VCardComposer(Context context, int vcardType) {
-        this(context, vcardType, null, true);
-    }
-
-    public VCardComposer(Context context, int vcardType, String charset) {
-        this(context, vcardType, charset, true);
-    }
-
-    /**
-     * The variant which sets charset to null.
-     */
-    public VCardComposer(final Context context, final int vcardType,
-            final boolean careHandlerErrors) {
-        this(context, vcardType, null, careHandlerErrors);
-    }
-
-    /**
-     * Construct for supporting call log entry vCard composing.
-     *
-     * @param context Context to be used during the composition.
-     * @param vcardType The type of vCard, typically available via {@link VCardConfig}.
-     * @param charset The charset to be used. Use null when you don't need the charset.
-     * @param careHandlerErrors If true, This object returns false everytime
-     * a Handler object given via {{@link #addHandler(OneEntryHandler)} returns false.
-     * If false, this ignores those errors.
-     */
-    public VCardComposer(final Context context, final int vcardType, String charset,
-            final boolean careHandlerErrors) {
-        mContext = context;
-        mVCardType = vcardType;
-        mCareHandlerErrors = careHandlerErrors;
-        mContentResolver = context.getContentResolver();
-
-        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
-        mHandlerList = new ArrayList<OneEntryHandler>();
-
-        charset = (TextUtils.isEmpty(charset) ? VCardConfig.DEFAULT_EXPORT_CHARSET : charset);
-        final boolean shouldAppendCharsetParam = !(
-                VCardConfig.isV30(vcardType) && UTF_8.equalsIgnoreCase(charset));
-
-        if (mIsDoCoMo || shouldAppendCharsetParam) {
-            if (SHIFT_JIS.equalsIgnoreCase(charset)) {
-                if (mIsDoCoMo) {
-                    try {
-                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
-                    } catch (UnsupportedCharsetException e) {
-                        Log.e(LOG_TAG,
-                                "DoCoMo-specific SHIFT_JIS was not found. "
-                                + "Use SHIFT_JIS as is.");
-                        charset = SHIFT_JIS;
-                    }
-                } else {
-                    try {
-                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
-                    } catch (UnsupportedCharsetException e) {
-                        Log.e(LOG_TAG,
-                                "Career-specific SHIFT_JIS was not found. "
-                                + "Use SHIFT_JIS as is.");
-                        charset = SHIFT_JIS;
-                    }
-                }
-                mCharset = charset;
-            } else {
-                Log.w(LOG_TAG,
-                        "The charset \"" + charset + "\" is used while "
-                        + SHIFT_JIS + " is needed to be used.");
-                if (TextUtils.isEmpty(charset)) {
-                    mCharset = SHIFT_JIS;
-                } else {
-                    try {
-                        charset = CharsetUtils.charsetForVendor(charset).name();
-                    } catch (UnsupportedCharsetException e) {
-                        Log.i(LOG_TAG,
-                                "Career-specific \"" + charset + "\" was not found (as usual). "
-                                + "Use it as is.");
-                    }
-                    mCharset = charset;
-                }
-            }
-        } else {
-            if (TextUtils.isEmpty(charset)) {
-                mCharset = UTF_8;
-            } else {
-                try {
-                    charset = CharsetUtils.charsetForVendor(charset).name();
-                } catch (UnsupportedCharsetException e) {
-                    Log.i(LOG_TAG,
-                            "Career-specific \"" + charset + "\" was not found (as usual). "
-                            + "Use it as is.");
-                }
-                mCharset = charset;
-            }
-        }
-
-        Log.d(LOG_TAG, "Use the charset \"" + mCharset + "\"");
-    }
-
-    /**
-     * Must be called before {@link #init()}.
-     */
-    public void addHandler(OneEntryHandler handler) {
-        if (handler != null) {
-            mHandlerList.add(handler);
-        }
-    }
-
-    /**
-     * @return Returns true when initialization is successful and all the other
-     *          methods are available. Returns false otherwise.
-     */
-    public boolean init() {
-        return init(null, null);
-    }
-
-    public boolean init(final String selection, final String[] selectionArgs) {
-        return init(Contacts.CONTENT_URI, selection, selectionArgs, null);
-    }
-
-    /**
-     * Note that this is unstable interface, may be deleted in the future.
-     */
-    public boolean init(final Uri contentUri, final String selection,
-            final String[] selectionArgs, final String sortOrder) {
-        if (contentUri == null) {
-            return false;
-        }
-
-        if (mCareHandlerErrors) {
-            final List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
-                    mHandlerList.size());
-            for (OneEntryHandler handler : mHandlerList) {
-                if (!handler.onInit(mContext)) {
-                    for (OneEntryHandler finished : finishedList) {
-                        finished.onTerminate();
-                    }
-                    return false;
-                }
-            }
-        } else {
-            // Just ignore the false returned from onInit().
-            for (OneEntryHandler handler : mHandlerList) {
-                handler.onInit(mContext);
-            }
-        }
-
-        final String[] projection;
-        if (Contacts.CONTENT_URI.equals(contentUri) ||
-                CONTACTS_TEST_CONTENT_URI.equals(contentUri)) {
-            projection = sContactsProjection;
-        } else {
-            mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
-            return false;
-        }
-        mCursor = mContentResolver.query(
-                contentUri, projection, selection, selectionArgs, sortOrder);
-
-        if (mCursor == null) {
-            mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
-            return false;
-        }
-
-        if (getCount() == 0 || !mCursor.moveToFirst()) {
-            try {
-                mCursor.close();
-            } catch (SQLiteException e) {
-                Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
-            } finally {
-                mCursor = null;
-                mErrorReason = FAILURE_REASON_NO_ENTRY;
-            }
-            return false;
-        }
-
-        mIdColumn = mCursor.getColumnIndex(Contacts._ID);
-
-        return true;
-    }
-
-    public boolean createOneEntry() {
-        return createOneEntry(null);
-    }
-
-    /**
-     * @param getEntityIteratorMethod For Dependency Injection.
-     * @hide just for testing.
-     */
-    public boolean createOneEntry(Method getEntityIteratorMethod) {
-        if (mCursor == null || mCursor.isAfterLast()) {
-            mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
-            return false;
-        }
-        final String vcard;
-        try {
-            if (mIdColumn >= 0) {
-                vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
-                        getEntityIteratorMethod);
-            } else {
-                Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
-                return true;
-            }
-        } catch (VCardException e) {
-            Log.e(LOG_TAG, "VCardException has been thrown: " + e.getMessage());
-            return false;
-        } catch (OutOfMemoryError error) {
-            // Maybe some data (e.g. photo) is too big to have in memory. But it
-            // should be rare.
-            Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry.");
-            System.gc();
-            // TODO: should tell users what happened?
-            return true;
-        } finally {
-            mCursor.moveToNext();
-        }
-
-        // This function does not care the OutOfMemoryError on the handler side :-P
-        if (mCareHandlerErrors) {
-            List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
-                    mHandlerList.size());
-            for (OneEntryHandler handler : mHandlerList) {
-                if (!handler.onEntryCreated(vcard)) {
-                    return false;
-                }
-            }
-        } else {
-            for (OneEntryHandler handler : mHandlerList) {
-                handler.onEntryCreated(vcard);
-            }
-        }
-
-        return true;
-    }
-
-    private String createOneEntryInternal(final String contactId,
-            final Method getEntityIteratorMethod) throws VCardException {
-        final Map<String, List<ContentValues>> contentValuesListMap =
-                new HashMap<String, List<ContentValues>>();
-        // The resolver may return the entity iterator with no data. It is possible.
-        // e.g. If all the data in the contact of the given contact id are not exportable ones,
-        //      they are hidden from the view of this method, though contact id itself exists.
-        EntityIterator entityIterator = null;
-        try {
-            final Uri uri = RawContactsEntity.CONTENT_URI.buildUpon()
-                    // .appendQueryParameter("for_export_only", "1")
-                    .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
-                    .build();
-            final String selection = Data.CONTACT_ID + "=?";
-            final String[] selectionArgs = new String[] {contactId};
-            if (getEntityIteratorMethod != null) {
-                // Please note that this branch is executed by unit tests only
-                try {
-                    entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
-                            mContentResolver, uri, selection, selectionArgs, null);
-                } catch (IllegalArgumentException e) {
-                    Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
-                            e.getMessage());
-                } catch (IllegalAccessException e) {
-                    Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
-                            e.getMessage());
-                } catch (InvocationTargetException e) {
-                    Log.e(LOG_TAG, "InvocationTargetException has been thrown: ");
-                    StackTraceElement[] stackTraceElements = e.getCause().getStackTrace();
-                    for (StackTraceElement element : stackTraceElements) {
-                        Log.e(LOG_TAG, "    at " + element.toString());
-                    }
-                    throw new VCardException("InvocationTargetException has been thrown: " +
-                            e.getCause().getMessage());
-                }
-            } else {
-                entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
-                        uri, null, selection, selectionArgs, null));
-            }
-
-            if (entityIterator == null) {
-                Log.e(LOG_TAG, "EntityIterator is null");
-                return "";
-            }
-
-            if (!entityIterator.hasNext()) {
-                Log.w(LOG_TAG, "Data does not exist. contactId: " + contactId);
-                return "";
-            }
-
-            while (entityIterator.hasNext()) {
-                Entity entity = entityIterator.next();
-                for (NamedContentValues namedContentValues : entity.getSubValues()) {
-                    ContentValues contentValues = namedContentValues.values;
-                    String key = contentValues.getAsString(Data.MIMETYPE);
-                    if (key != null) {
-                        List<ContentValues> contentValuesList =
-                                contentValuesListMap.get(key);
-                        if (contentValuesList == null) {
-                            contentValuesList = new ArrayList<ContentValues>();
-                            contentValuesListMap.put(key, contentValuesList);
-                        }
-                        contentValuesList.add(contentValues);
-                    }
-                }
-            }
-        } finally {
-            if (entityIterator != null) {
-                entityIterator.close();
-            }
-        }
-
-        return buildVCard(contentValuesListMap);
-    }
-
-    /**
-     * Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
-     * {ContactsContract}. Developers can override this method to customize the output.
-     */
-    public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
-        if (contentValuesListMap == null) {
-            Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
-            return "";
-        } else {
-            final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
-            builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
-                    .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
-                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
-                    .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
-                    .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
-                    .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
-                    .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE))
-                    .appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE))
-                    .appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
-                    .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
-                    .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
-                    .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
-            return builder.toString();
-        }
-    }
-
-    public void terminate() {
-        for (OneEntryHandler handler : mHandlerList) {
-            handler.onTerminate();
-        }
-
-        if (mCursor != null) {
-            try {
-                mCursor.close();
-            } catch (SQLiteException e) {
-                Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
-            }
-            mCursor = null;
-        }
-
-        mTerminateIsCalled = true;
-    }
-
-    @Override
-    public void finalize() {
-        if (!mTerminateIsCalled) {
-            Log.w(LOG_TAG, "terminate() is not called yet. We call it in finalize() step.");
-            terminate();
-        }
-    }
-
-    /**
-     * @return returns the number of available entities. The return value is undefined
-     * when this object is not ready yet (typically when {{@link #init()} is not called
-     * or when {@link #terminate()} is already called).
-     */
-    public int getCount() {
-        if (mCursor == null) {
-            Log.w(LOG_TAG, "This object is not ready yet.");
-            return 0;
-        }
-        return mCursor.getCount();
-    }
-
-    /**
-     * @return true when there's no entity to be built. The return value is undefined
-     * when this object is not ready yet.
-     */
-    public boolean isAfterLast() {
-        if (mCursor == null) {
-            Log.w(LOG_TAG, "This object is not ready yet.");
-            return false;
-        }
-        return mCursor.isAfterLast();
-    }
-
-    /**
-     * @return Returns the error reason.
-     */
-    public String getErrorReason() {
-        return mErrorReason;
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardConfig.java b/vcard/java/com/android/vcard/VCardConfig.java
deleted file mode 100644
index a011d8e..0000000
--- a/vcard/java/com/android/vcard/VCardConfig.java
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.telephony.PhoneNumberUtils;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * The class representing VCard related configurations. Useful static methods are not in this class
- * but in VCardUtils.
- */
-public class VCardConfig {
-    private static final String LOG_TAG = "VCardConfig";
-
-    /* package */ static final int LOG_LEVEL_NONE = 0;
-    /* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
-    /* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2;
-    /* package */ static final int LOG_LEVEL_VERBOSE =
-        LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
-
-    /* package */ static final int LOG_LEVEL = LOG_LEVEL_NONE;
-
-    /**
-     * <p>
-     * The charset used during import.
-     * </p>
-     * <p>
-     * We cannot determine which charset should be used to interpret lines in vCard,
-     * while Java requires us to specify it when InputStream is used.
-     * We need to rely on the mechanism due to some performance reason.
-     * </p>
-     * <p>
-     * In order to avoid "misinterpretation" of charset and lose any data in vCard,
-     * "ISO-8859-1" is first used for reading the stream.
-     * When a charset is specified in a property (with "CHARSET=..." parameter),
-     * the string is decoded to raw bytes and encoded into the specific charset,
-     * </p>
-     * <p>
-     * Unicode specification there's a one to one mapping between each byte in ISO-8859-1
-     * and a codepoint, and Java specification requires runtime must have the charset.
-     * Thus, ISO-8859-1 is one effective mapping for intermediate mapping.
-     * </p>
-     */
-    public static final String DEFAULT_INTERMEDIATE_CHARSET = "ISO-8859-1";
-
-    /**
-     * The charset used when there's no information affbout what charset should be used to
-     * encode the binary given from vCard.
-     */
-    public static final String DEFAULT_IMPORT_CHARSET = "UTF-8";
-    public static final String DEFAULT_EXPORT_CHARSET = "UTF-8";
-
-    public static final int FLAG_V21 = 0;
-    public static final int FLAG_V30 = 1;
-
-    // 0x2 is reserved for the future use ...
-
-    public static final int NAME_ORDER_DEFAULT = 0;
-    public static final int NAME_ORDER_EUROPE = 0x4;
-    public static final int NAME_ORDER_JAPANESE = 0x8;
-    private static final int NAME_ORDER_MASK = 0xC;
-
-    // 0x10 is reserved for safety
-
-    /**
-     * <p>
-     * The flag indicating the vCard composer will add some "X-" properties used only in Android
-     * when the formal vCard specification does not have appropriate fields for that data.
-     * </p>
-     * <p>
-     * For example, Android accepts nickname information while vCard 2.1 does not.
-     * When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME")
-     * instead of just dropping it.
-     * </p>
-     * <p>
-     * vCard parser code automatically parses the field emitted even when this flag is off.
-     * </p>
-     */
-    private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000;
-    
-    /**
-     * <p>
-     * The flag indicating the vCard composer will add some "X-" properties seen in the
-     * vCard data emitted by the other softwares/devices when the formal vCard specification
-     * does not have appropriate field(s) for that data.
-     * </p> 
-     * <p>
-     * One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are
-     * for phonetic name (how the name is pronounced), seen in the vCard emitted by some other
-     * non-Android devices/softwares. We chose to enable the vCard composer to use those
-     * defact properties since they are also useful for Android devices.
-     * </p>
-     * <p>
-     * Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0
-     * allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens
-     * in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties.
-     * </p>
-     */
-    private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000;
-
-    /**
-     * <p>
-     * The flag indicating some specific dialect seen in vCard of DoCoMo (one of Japanese
-     * mobile careers) should be used. This flag does not include any other information like
-     * that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's
-     * dialect but the name order should be European", but it is not recommended.
-     * </p>
-     */
-    private static final int FLAG_DOCOMO = 0x20000000;
-
-    /**
-     * <p>
-     * The flag indicating the vCard composer does "NOT" use Quoted-Printable toward "primary"
-     * properties even though it is required by vCard 2.1 (QP is prohibited in vCard 3.0).
-     * </p>
-     * <p>
-     * We actually cannot define what is the "primary" property. Note that this is NOT defined
-     * in vCard specification either. Also be aware that it is NOT related to "primary" notion
-     * used in {@link android.provider.ContactsContract}.
-     * This notion is just for vCard composition in Android.
-     * </p>
-     * <p>
-     * We added this Android-specific notion since some (incomplete) vCard exporters for vCard 2.1
-     * do NOT use Quoted-Printable encoding toward some properties related names like "N", "FN", etc.
-     * even when their values contain non-ascii or/and CR/LF, while they use the encoding in the
-     * other properties like "ADR", "ORG", etc.
-     * <p>
-     * We are afraid of the case where some vCard importer also forget handling QP presuming QP is
-     * not used in such fields.
-     * </p>
-     * <p>
-     * This flag is useful when some target importer you are going to focus on does not accept
-     * such properties with Quoted-Printable encoding.
-     * </p>
-     * <p>
-     * Again, we should not use this flag at all for complying vCard 2.1 spec.
-     * </p>
-     * <p>
-     * In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this
-     * kind of problem (hopefully).
-     * </p>
-     * @hide
-     */
-    public static final int FLAG_REFRAIN_QP_TO_NAME_PROPERTIES = 0x10000000;
-
-    /**
-     * <p>
-     * The flag indicating that phonetic name related fields must be converted to
-     * appropriate form. Note that "appropriate" is not defined in any vCard specification.
-     * This is Android-specific.
-     * </p>
-     * <p>
-     * One typical (and currently sole) example where we need this flag is the time when
-     * we need to emit Japanese phonetic names into vCard entries. The property values
-     * should be encoded into half-width katakana when the target importer is Japanese mobile
-     * phones', which are probably not able to parse full-width hiragana/katakana for
-     * historical reasons, while the vCard importers embedded to softwares for PC should be
-     * able to parse them as we expect.
-     * </p>
-     */
-    public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x08000000;
-
-    /**
-     * <p>
-     * The flag indicating the vCard composer "for 2.1" emits "TYPE=" string toward TYPE params
-     * every time possible. The default behavior does not emit it and is valid in the spec.
-     * In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in vCard 3.0 specification.
-     * </p>
-     * <p>
-     * Detail:
-     * How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0.
-     * </p>
-     * <p>
-     * e.g.
-     * </p>
-     * <ol>
-     * <li>Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."</li>
-     * <li>Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."</li>
-     * <li>Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."</li>
-     * </ol>
-     * <p>
-     * If you are targeting to the importer which cannot accept TYPE params without "TYPE="
-     * strings (which should be rare though), please use this flag.
-     * </p>
-     * <p>
-     * Example usage:
-     * <pre class="prettyprint">int type = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);</pre>
-     * </p>
-     */
-    public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000;
-
-    /**
-     * <p>
-     * The flag indicating the vCard composer does touch nothing toward phone number Strings
-     * but leave it as is.
-     * </p>
-     * <p>
-     * The vCard specifications mention nothing toward phone numbers, while some devices
-     * do (wrongly, but with innevitable reasons).
-     * For example, there's a possibility Japanese mobile phones are expected to have
-     * just numbers, hypens, plus, etc. but not usual alphabets, while US mobile phones
-     * should get such characters. To make exported vCard simple for external parsers,
-     * we have used {@link PhoneNumberUtils#formatNumber(String)} during export, and
-     * removed unnecessary characters inside the number (e.g. "111-222-3333 (Miami)"
-     * becomes "111-222-3333").
-     * Unfortunate side effect of that use was some control characters used in the other
-     * areas may be badly affected by the formatting.
-     * </p>
-     * <p>
-     * This flag disables that formatting, affecting both importer and exporter.
-     * If the user is aware of some side effects due to the implicit formatting, use this flag.
-     * </p>
-     */
-    public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000;
-
-    /**
-     * <p>
-     * For importer only. Ignored in exporter.
-     * </p>
-     * <p>
-     * The flag indicating the parser should handle a nested vCard, in which vCard clause starts
-     * in another vCard clause. Here's a typical example.
-     * </p>
-     * <pre class="prettyprint">BEGIN:VCARD
-     * BEGIN:VCARD
-     * VERSION:2.1
-     * ...
-     * END:VCARD
-     * END:VCARD</pre>
-     * <p>
-     * The vCard 2.1 specification allows the nest, but also let parsers ignore nested entries,
-     * while some mobile devices emit nested ones as primary data to be imported.
-     * </p>
-     * <p>
-     * This flag forces a vCard parser to torelate such a nest and understand its content.
-     * </p>
-     */
-    public static final int FLAG_TORELATE_NEST = 0x01000000;
-
-    //// The followings are VCard types available from importer/exporter. ////
-
-    /**
-     * <p>
-     * The type indicating nothing. Used by {@link VCardSourceDetector} when it
-     * was not able to guess the exact vCard type.
-     * </p>
-     */
-    public static final int VCARD_TYPE_UNKNOWN = 0;
-
-    /**
-     * <p>
-     * Generic vCard format with the vCard 2.1. When composing a vCard entry,
-     * the US convension will be used toward formatting some values.
-     * </p>
-     * <p>
-     * e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
-     * while it should be "Prefix Family Middle Given Suffix" in Japan for example.
-     * </p>
-     * <p>
-     * Uses UTF-8 for the charset as a charset for exporting. Note that old vCard importer
-     * outside Android cannot accept it since vCard 2.1 specifically does not allow
-     * that charset, while we need to use it to support various languages around the world.
-     * </p>
-     * <p>
-     * If you want to use alternative charset, you should notify the charset to the other
-     * compontent to be used.
-     * </p>
-     */
-    public static final int VCARD_TYPE_V21_GENERIC =
-        (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
-    /* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic";
-    
-    /**
-     * <p>
-     * General vCard format with the version 3.0. Uses UTF-8 for the charset.
-     * </p>
-     * <p>
-     * Not fully ready yet. Use with caution when you use this.
-     * </p>
-     */
-    public static final int VCARD_TYPE_V30_GENERIC =
-        (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
-    /* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic";
-    
-    /**
-     * <p>
-     * General vCard format for the vCard 2.1 with some Europe convension. Uses Utf-8.
-     * Currently, only name order is considered ("Prefix Middle Given Family Suffix")
-     * </p>
-     */
-    public static final int VCARD_TYPE_V21_EUROPE =
-        (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
-    /* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe";
-    
-    /**
-     * <p>
-     * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8.
-     * </p>
-     * <p>
-     * Not ready yet. Use with caution when you use this.
-     * </p>
-     */
-    public static final int VCARD_TYPE_V30_EUROPE =
-        (FLAG_V30 | NAME_ORDER_EUROPE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-    
-    /* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
-
-    /**
-     * <p>
-     * The vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
-     * </p>
-     * <p>
-     * Not ready yet. Use with caution when you use this.
-     * </p>
-     */
-    public static final int VCARD_TYPE_V21_JAPANESE =
-        (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
-    /* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese_utf8";
-
-    /**
-     * <p>
-     * The vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
-     * </p>
-     * <p>
-     * Not ready yet. Use with caution when you use this.
-     * </p>
-     */
-    public static final int VCARD_TYPE_V30_JAPANESE =
-        (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
-    /* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese_utf8";
-
-    /**
-     * <p>
-     * The vCard 2.1 based format which (partially) considers the convention in Japanese
-     * mobile phones, where phonetic names are translated to half-width katakana if
-     * possible, etc. It would be better to use Shift_JIS as a charset for maximum
-     * compatibility.
-     * </p>
-     * @hide Should not be available world wide.
-     */
-    public static final int VCARD_TYPE_V21_JAPANESE_MOBILE =
-        (FLAG_V21 | NAME_ORDER_JAPANESE |
-                FLAG_CONVERT_PHONETIC_NAME_STRINGS | FLAG_REFRAIN_QP_TO_NAME_PROPERTIES);
-
-    /* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
-
-    /**
-     * <p>
-     * The vCard format used in DoCoMo, which is one of Japanese mobile phone careers.
-     * </p>
-     * <p>
-     * Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
-     * No Android-specific property nor defact property is included. The "Primary" properties
-     * are NOT encoded to Quoted-Printable.
-     * </p>
-     * @hide Should not be available world wide.
-     */
-    public static final int VCARD_TYPE_DOCOMO =
-        (VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO);
-
-    /* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo";
-
-    public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC;
-
-    private static final Map<String, Integer> sVCardTypeMap;
-    private static final Set<Integer> sJapaneseMobileTypeSet;
-    
-    static {
-        sVCardTypeMap = new HashMap<String, Integer>();
-        sVCardTypeMap.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC);
-        sVCardTypeMap.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC);
-        sVCardTypeMap.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE);
-        sVCardTypeMap.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE);
-        sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE);
-        sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE);
-        sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_MOBILE_STR, VCARD_TYPE_V21_JAPANESE_MOBILE);
-        sVCardTypeMap.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
-
-        sJapaneseMobileTypeSet = new HashSet<Integer>();
-        sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE);
-        sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE);
-        sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_MOBILE);
-        sJapaneseMobileTypeSet.add(VCARD_TYPE_DOCOMO);
-    }
-
-    public static int getVCardTypeFromString(final String vcardTypeString) {
-        final String loweredKey = vcardTypeString.toLowerCase();
-        if (sVCardTypeMap.containsKey(loweredKey)) {
-            return sVCardTypeMap.get(loweredKey);
-        } else if ("default".equalsIgnoreCase(vcardTypeString)) {
-            return VCARD_TYPE_DEFAULT;
-        } else {
-            Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\"");
-            return VCARD_TYPE_DEFAULT;
-        }
-    }
-
-    public static boolean isV30(final int vcardType) {
-        return ((vcardType & FLAG_V30) != 0);  
-    }
-
-    public static boolean shouldUseQuotedPrintable(final int vcardType) {
-        return !isV30(vcardType);
-    }
-
-    public static int getNameOrderType(final int vcardType) {
-        return vcardType & NAME_ORDER_MASK;
-    }
-
-    public static boolean usesAndroidSpecificProperty(final int vcardType) {
-        return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0);
-    }
-
-    public static boolean usesDefactProperty(final int vcardType) {
-        return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
-    }
-
-    public static boolean showPerformanceLog() {
-        return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
-    }
-
-    public static boolean shouldRefrainQPToNameProperties(final int vcardType) {
-       return (!shouldUseQuotedPrintable(vcardType) ||
-               ((vcardType & FLAG_REFRAIN_QP_TO_NAME_PROPERTIES) != 0));
-    }
-
-    public static boolean appendTypeParamName(final int vcardType) {
-        return (isV30(vcardType) || ((vcardType & FLAG_APPEND_TYPE_PARAM) != 0));
-    }
-
-    /**
-     * @return true if the device is Japanese and some Japanese convension is
-     * applied to creating "formatted" something like FORMATTED_ADDRESS.
-     */
-    public static boolean isJapaneseDevice(final int vcardType) {
-        // TODO: Some mask will be required so that this method wrongly interpret
-        //        Japanese"-like" vCard type.
-        //        e.g. VCARD_TYPE_V21_JAPANESE_SJIS | FLAG_APPEND_TYPE_PARAMS
-        return sJapaneseMobileTypeSet.contains(vcardType);
-    }
-
-    /* package */ static boolean refrainPhoneNumberFormatting(final int vcardType) {
-        return ((vcardType & FLAG_REFRAIN_PHONE_NUMBER_FORMATTING) != 0);
-    }
-
-    public static boolean needsToConvertPhoneticString(final int vcardType) {
-        return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0);
-    }
-
-    public static boolean onlyOneNoteFieldIsAvailable(final int vcardType) {
-        return vcardType == VCARD_TYPE_DOCOMO;
-    }
-
-    public static boolean isDoCoMo(final int vcardType) {
-        return ((vcardType & FLAG_DOCOMO) != 0);
-    }
-
-    private VCardConfig() {
-    }
-}
\ No newline at end of file
diff --git a/vcard/java/com/android/vcard/VCardConstants.java b/vcard/java/com/android/vcard/VCardConstants.java
deleted file mode 100644
index 862c9edc..0000000
--- a/vcard/java/com/android/vcard/VCardConstants.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-/**
- * Constants used in both exporter and importer code.
- */
-public class VCardConstants {
-    public static final String VERSION_V21 = "2.1";
-    public static final String VERSION_V30 = "3.0";
-
-    // The property names valid both in vCard 2.1 and 3.0.
-    public static final String PROPERTY_BEGIN = "BEGIN";
-    public static final String PROPERTY_VERSION = "VERSION";
-    public static final String PROPERTY_N = "N";
-    public static final String PROPERTY_FN = "FN";
-    public static final String PROPERTY_ADR = "ADR";
-    public static final String PROPERTY_EMAIL = "EMAIL";
-    public static final String PROPERTY_NOTE = "NOTE";
-    public static final String PROPERTY_ORG = "ORG";
-    public static final String PROPERTY_SOUND = "SOUND";  // Not fully supported.
-    public static final String PROPERTY_TEL = "TEL";
-    public static final String PROPERTY_TITLE = "TITLE";
-    public static final String PROPERTY_ROLE = "ROLE";
-    public static final String PROPERTY_PHOTO = "PHOTO";
-    public static final String PROPERTY_LOGO = "LOGO";
-    public static final String PROPERTY_URL = "URL";
-    public static final String PROPERTY_BDAY = "BDAY";  // Birthday
-    public static final String PROPERTY_END = "END";
-
-    // Valid property names not supported (not appropriately handled) by our vCard importer now.
-    public static final String PROPERTY_REV = "REV";
-    public static final String PROPERTY_AGENT = "AGENT";
-
-    // Available in vCard 3.0. Shoud not use when composing vCard 2.1 file.
-    public static final String PROPERTY_NAME = "NAME";
-    public static final String PROPERTY_NICKNAME = "NICKNAME";
-    public static final String PROPERTY_SORT_STRING = "SORT-STRING";
-    
-    // De-fact property values expressing phonetic names.
-    public static final String PROPERTY_X_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME";
-    public static final String PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME";
-    public static final String PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
-
-    // Properties both ContactsStruct in Eclair and de-fact vCard extensions
-    // shown in http://en.wikipedia.org/wiki/VCard support are defined here.
-    public static final String PROPERTY_X_AIM = "X-AIM";
-    public static final String PROPERTY_X_MSN = "X-MSN";
-    public static final String PROPERTY_X_YAHOO = "X-YAHOO";
-    public static final String PROPERTY_X_ICQ = "X-ICQ";
-    public static final String PROPERTY_X_JABBER = "X-JABBER";
-    public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
-    public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
-    // Properties only ContactsStruct has. We alse use this.
-    public static final String PROPERTY_X_QQ = "X-QQ";
-    public static final String PROPERTY_X_NETMEETING = "X-NETMEETING";
-
-    // Phone number for Skype, available as usual phone.
-    public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
-
-    // Property for Android-specific fields.
-    public static final String PROPERTY_X_ANDROID_CUSTOM = "X-ANDROID-CUSTOM";
-
-    // Properties for DoCoMo vCard.
-    public static final String PROPERTY_X_CLASS = "X-CLASS";
-    public static final String PROPERTY_X_REDUCTION = "X-REDUCTION";
-    public static final String PROPERTY_X_NO = "X-NO";
-    public static final String PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
-
-    public static final String PARAM_TYPE = "TYPE";
-
-    public static final String PARAM_TYPE_HOME = "HOME";
-    public static final String PARAM_TYPE_WORK = "WORK";
-    public static final String PARAM_TYPE_FAX = "FAX";
-    public static final String PARAM_TYPE_CELL = "CELL";
-    public static final String PARAM_TYPE_VOICE = "VOICE";
-    public static final String PARAM_TYPE_INTERNET = "INTERNET";
-
-    // Abbreviation of "prefered" according to vCard 2.1 specification.
-    // We interpret this value as "primary" property during import/export.
-    //
-    // Note: Both vCard specs does not mention anything about the requirement for this parameter,
-    //       but there may be some vCard importer which will get confused with more than
-    //       one "PREF"s in one property name, while Android accepts them.
-    public static final String PARAM_TYPE_PREF = "PREF";
-
-    // Phone type parameters valid in vCard and known to ContactsContract, but not so common.
-    public static final String PARAM_TYPE_CAR = "CAR";
-    public static final String PARAM_TYPE_ISDN = "ISDN";
-    public static final String PARAM_TYPE_PAGER = "PAGER";
-    public static final String PARAM_TYPE_TLX = "TLX";  // Telex
-
-    // Phone types existing in vCard 2.1 but not known to ContactsContract.
-    public static final String PARAM_TYPE_MODEM = "MODEM";
-    public static final String PARAM_TYPE_MSG = "MSG";
-    public static final String PARAM_TYPE_BBS = "BBS";
-    public static final String PARAM_TYPE_VIDEO = "VIDEO";
-
-    public static final String PARAM_ENCODING_7BIT = "7BIT";
-    public static final String PARAM_ENCODING_8BIT = "8BIT";
-    public static final String PARAM_ENCODING_QP = "QUOTED-PRINTABLE";
-    public static final String PARAM_ENCODING_BASE64 = "BASE64";  // Available in vCard 2.1
-    public static final String PARAM_ENCODING_B = "B";  // Available in vCard 3.0
-
-    // TYPE parameters for Phones, which are not formally valid in vCard (at least 2.1).
-    // These types are basically encoded to "X-" parameters when composing vCard.
-    // Parser passes these when "X-" is added to the parameter or not.
-    public static final String PARAM_PHONE_EXTRA_TYPE_CALLBACK = "CALLBACK";
-    public static final String PARAM_PHONE_EXTRA_TYPE_RADIO = "RADIO";
-    public static final String PARAM_PHONE_EXTRA_TYPE_TTY_TDD = "TTY-TDD";
-    public static final String PARAM_PHONE_EXTRA_TYPE_ASSISTANT = "ASSISTANT";
-    // vCard composer translates this type to "WORK" + "PREF". Just for parsing.
-    public static final String PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN = "COMPANY-MAIN";
-    // vCard composer translates this type to "VOICE" Just for parsing.
-    public static final String PARAM_PHONE_EXTRA_TYPE_OTHER = "OTHER";
-
-    // TYPE parameters for postal addresses.
-    public static final String PARAM_ADR_TYPE_PARCEL = "PARCEL";
-    public static final String PARAM_ADR_TYPE_DOM = "DOM";
-    public static final String PARAM_ADR_TYPE_INTL = "INTL";
-
-    // TYPE parameters not officially valid but used in some vCard exporter.
-    // Do not use in composer side.
-    public static final String PARAM_EXTRA_TYPE_COMPANY = "COMPANY";
-
-    public interface ImportOnly {
-        public static final String PROPERTY_X_NICKNAME = "X-NICKNAME";
-        // Some device emits this "X-" parameter for expressing Google Talk,
-        // which is specifically invalid but should be always properly accepted, and emitted
-        // in some special case (for that device/application).
-        public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
-    }
-
-    //// Mainly for package constants.
-
-    // DoCoMo specific type parameter. Used with "SOUND" property, which is alternate of
-    // SORT-STRING invCard 3.0.
-    /* package */ static final String PARAM_TYPE_X_IRMC_N = "X-IRMC-N";
-
-    /* package */ static final int MAX_DATA_COLUMN = 15;
-
-    /* package */ static final int MAX_CHARACTER_NUMS_QP = 76;
-    static final int MAX_CHARACTER_NUMS_BASE64_V30 = 75;
-
-    private VCardConstants() {
-    }
-}
\ No newline at end of file
diff --git a/vcard/java/com/android/vcard/VCardEntry.java b/vcard/java/com/android/vcard/VCardEntry.java
deleted file mode 100644
index 624407a..0000000
--- a/vcard/java/com/android/vcard/VCardEntry.java
+++ /dev/null
@@ -1,1423 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.accounts.Account;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.OperationApplicationException;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class bridges between data structure of Contact app and VCard data.
- */
-public class VCardEntry {
-    private static final String LOG_TAG = "VCardEntry";
-
-    private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK;
-
-    private static final Map<String, Integer> sImMap = new HashMap<String, Integer>();
-
-    static {
-        sImMap.put(VCardConstants.PROPERTY_X_AIM, Im.PROTOCOL_AIM);
-        sImMap.put(VCardConstants.PROPERTY_X_MSN, Im.PROTOCOL_MSN);
-        sImMap.put(VCardConstants.PROPERTY_X_YAHOO, Im.PROTOCOL_YAHOO);
-        sImMap.put(VCardConstants.PROPERTY_X_ICQ, Im.PROTOCOL_ICQ);
-        sImMap.put(VCardConstants.PROPERTY_X_JABBER, Im.PROTOCOL_JABBER);
-        sImMap.put(VCardConstants.PROPERTY_X_SKYPE_USERNAME, Im.PROTOCOL_SKYPE);
-        sImMap.put(VCardConstants.PROPERTY_X_GOOGLE_TALK, Im.PROTOCOL_GOOGLE_TALK);
-        sImMap.put(VCardConstants.ImportOnly.PROPERTY_X_GOOGLE_TALK_WITH_SPACE,
-                Im.PROTOCOL_GOOGLE_TALK);
-    }
-
-    public static class PhoneData {
-        public final int type;
-        public final String data;
-        public final String label;
-        // isPrimary is (not final but) changable, only when there's no appropriate one existing
-        // in the original VCard.
-        public boolean isPrimary;
-        public PhoneData(int type, String data, String label, boolean isPrimary) {
-            this.type = type;
-            this.data = data;
-            this.label = label;
-            this.isPrimary = isPrimary;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof PhoneData)) {
-                return false;
-            }
-            PhoneData phoneData = (PhoneData)obj;
-            return (type == phoneData.type && data.equals(phoneData.data) &&
-                    label.equals(phoneData.label) && isPrimary == phoneData.isPrimary);
-        }
-
-        @Override
-        public String toString() {
-            return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
-                    type, data, label, isPrimary);
-        }
-    }
-
-    public static class EmailData {
-        public final int type;
-        public final String data;
-        // Used only when TYPE is TYPE_CUSTOM.
-        public final String label;
-        public boolean isPrimary;
-        public EmailData(int type, String data, String label, boolean isPrimary) {
-            this.type = type;
-            this.data = data;
-            this.label = label;
-            this.isPrimary = isPrimary;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof EmailData)) {
-                return false;
-            }
-            EmailData emailData = (EmailData)obj;
-            return (type == emailData.type && data.equals(emailData.data) &&
-                    label.equals(emailData.label) && isPrimary == emailData.isPrimary);
-        }
-
-        @Override
-        public String toString() {
-            return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
-                    type, data, label, isPrimary);
-        }
-    }
-
-    public static class PostalData {
-        // Determined by vCard specification.
-        // - PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name
-        public static final int ADDR_MAX_DATA_SIZE = 7;
-        private final String[] dataArray;
-        public final String pobox;
-        public final String extendedAddress;
-        public final String street;
-        public final String localty;
-        public final String region;
-        public final String postalCode;
-        public final String country;
-        public final int type;
-        public final String label;
-        public boolean isPrimary;
-
-        public PostalData(final int type, final List<String> propValueList,
-                final String label, boolean isPrimary) {
-            this.type = type;
-            dataArray = new String[ADDR_MAX_DATA_SIZE];
-
-            int size = propValueList.size();
-            if (size > ADDR_MAX_DATA_SIZE) {
-                size = ADDR_MAX_DATA_SIZE;
-            }
-
-            // adr-value = 0*6(text-value ";") text-value
-            //           ; PO Box, Extended Address, Street, Locality, Region, Postal
-            //           ; Code, Country Name
-            //
-            // Use Iterator assuming List may be LinkedList, though actually it is
-            // always ArrayList in the current implementation.
-            int i = 0;
-            for (String addressElement : propValueList) {
-                dataArray[i] = addressElement;
-                if (++i >= size) {
-                    break;
-                }
-            }
-            while (i < ADDR_MAX_DATA_SIZE) {
-                dataArray[i++] = null;
-            }
-
-            this.pobox = dataArray[0];
-            this.extendedAddress = dataArray[1];
-            this.street = dataArray[2];
-            this.localty = dataArray[3];
-            this.region = dataArray[4];
-            this.postalCode = dataArray[5];
-            this.country = dataArray[6];
-            this.label = label;
-            this.isPrimary = isPrimary;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof PostalData)) {
-                return false;
-            }
-            final PostalData postalData = (PostalData)obj;
-            return (Arrays.equals(dataArray, postalData.dataArray) &&
-                    (type == postalData.type &&
-                            (type == StructuredPostal.TYPE_CUSTOM ?
-                                    (label == postalData.label) : true)) &&
-                    (isPrimary == postalData.isPrimary));
-        }
-
-        public String getFormattedAddress(final int vcardType) {
-            StringBuilder builder = new StringBuilder();
-            boolean empty = true;
-            if (VCardConfig.isJapaneseDevice(vcardType)) {
-                // In Japan, the order is reversed.
-                for (int i = ADDR_MAX_DATA_SIZE - 1; i >= 0; i--) {
-                    String addressPart = dataArray[i];
-                    if (!TextUtils.isEmpty(addressPart)) {
-                        if (!empty) {
-                            builder.append(' ');
-                        } else {
-                            empty = false;
-                        }
-                        builder.append(addressPart);
-                    }
-                }
-            } else {
-                for (int i = 0; i < ADDR_MAX_DATA_SIZE; i++) {
-                    String addressPart = dataArray[i];
-                    if (!TextUtils.isEmpty(addressPart)) {
-                        if (!empty) {
-                            builder.append(' ');
-                        } else {
-                            empty = false;
-                        }
-                        builder.append(addressPart);
-                    }
-                }
-            }
-
-            return builder.toString().trim();
-        }
-
-        @Override
-        public String toString() {
-            return String.format("type: %d, label: %s, isPrimary: %s",
-                    type, label, isPrimary);
-        }
-    }
-
-    public static class OrganizationData {
-        public final int type;
-        // non-final is Intentional: we may change the values since this info is separated into
-        // two parts in vCard: "ORG" + "TITLE", and we have to cope with each field in
-        // different timing.
-        public String companyName;
-        public String departmentName;
-        public String titleName;
-        public boolean isPrimary;
-
-        public OrganizationData(int type,
-                String companyName,
-                String departmentName,
-                String titleName,
-                boolean isPrimary) {
-            this.type = type;
-            this.companyName = companyName;
-            this.departmentName = departmentName;
-            this.titleName = titleName;
-            this.isPrimary = isPrimary;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof OrganizationData)) {
-                return false;
-            }
-            OrganizationData organization = (OrganizationData)obj;
-            return (type == organization.type &&
-                    TextUtils.equals(companyName, organization.companyName) &&
-                    TextUtils.equals(departmentName, organization.departmentName) &&
-                    TextUtils.equals(titleName, organization.titleName) &&
-                    isPrimary == organization.isPrimary);
-        }
-
-        public String getFormattedString() {
-            final StringBuilder builder = new StringBuilder();
-            if (!TextUtils.isEmpty(companyName)) {
-                builder.append(companyName);
-            }
-
-            if (!TextUtils.isEmpty(departmentName)) {
-                if (builder.length() > 0) {
-                    builder.append(", ");
-                }
-                builder.append(departmentName);
-            }
-
-            if (!TextUtils.isEmpty(titleName)) {
-                if (builder.length() > 0) {
-                    builder.append(", ");
-                }
-                builder.append(titleName);
-            }
-
-            return builder.toString();
-        }
-
-        @Override
-        public String toString() {
-            return String.format(
-                    "type: %d, company: %s, department: %s, title: %s, isPrimary: %s",
-                    type, companyName, departmentName, titleName, isPrimary);
-        }
-    }
-
-    public static class ImData {
-        public final int protocol;
-        public final String customProtocol;
-        public final int type;
-        public final String data;
-        public final boolean isPrimary;
-
-        public ImData(final int protocol, final String customProtocol, final int type,
-                final String data, final boolean isPrimary) {
-            this.protocol = protocol;
-            this.customProtocol = customProtocol;
-            this.type = type;
-            this.data = data;
-            this.isPrimary = isPrimary;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ImData)) {
-                return false;
-            }
-            ImData imData = (ImData)obj;
-            return (type == imData.type && protocol == imData.protocol
-                    && (customProtocol != null ? customProtocol.equals(imData.customProtocol) :
-                        (imData.customProtocol == null))
-                    && (data != null ? data.equals(imData.data) : (imData.data == null))
-                    && isPrimary == imData.isPrimary);
-        }
-
-        @Override
-        public String toString() {
-            return String.format(
-                    "type: %d, protocol: %d, custom_protcol: %s, data: %s, isPrimary: %s",
-                    type, protocol, customProtocol, data, isPrimary);
-        }
-    }
-
-    public static class PhotoData {
-        public static final String FORMAT_FLASH = "SWF";
-        public final int type;
-        public final String formatName;  // used when type is not defined in ContactsContract.
-        public final byte[] photoBytes;
-        public final boolean isPrimary;
-
-        public PhotoData(int type, String formatName, byte[] photoBytes, boolean isPrimary) {
-            this.type = type;
-            this.formatName = formatName;
-            this.photoBytes = photoBytes;
-            this.isPrimary = isPrimary;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof PhotoData)) {
-                return false;
-            }
-            PhotoData photoData = (PhotoData)obj;
-            return (type == photoData.type &&
-                    (formatName == null ? (photoData.formatName == null) :
-                            formatName.equals(photoData.formatName)) &&
-                    (Arrays.equals(photoBytes, photoData.photoBytes)) &&
-                    (isPrimary == photoData.isPrimary));
-        }
-
-        @Override
-        public String toString() {
-            return String.format("type: %d, format: %s: size: %d, isPrimary: %s",
-                    type, formatName, photoBytes.length, isPrimary);
-        }
-    }
-
-    /* package */ static class Property {
-        private String mPropertyName;
-        private Map<String, Collection<String>> mParameterMap =
-            new HashMap<String, Collection<String>>();
-        private List<String> mPropertyValueList = new ArrayList<String>();
-        private byte[] mPropertyBytes;
-
-        public void setPropertyName(final String propertyName) {
-            mPropertyName = propertyName;
-        }
-
-        public void addParameter(final String paramName, final String paramValue) {
-            Collection<String> values;
-            if (!mParameterMap.containsKey(paramName)) {
-                if (paramName.equals("TYPE")) {
-                    values = new HashSet<String>();
-                } else {
-                    values = new ArrayList<String>();
-                }
-                mParameterMap.put(paramName, values);
-            } else {
-                values = mParameterMap.get(paramName);
-            }
-            values.add(paramValue);
-        }
-
-        public void addToPropertyValueList(final String propertyValue) {
-            mPropertyValueList.add(propertyValue);
-        }
-
-        public void setPropertyBytes(final byte[] propertyBytes) {
-            mPropertyBytes = propertyBytes;
-        }
-
-        public final Collection<String> getParameters(String type) {
-            return mParameterMap.get(type);
-        }
-
-        public final List<String> getPropertyValueList() {
-            return mPropertyValueList;
-        }
-
-        public void clear() {
-            mPropertyName = null;
-            mParameterMap.clear();
-            mPropertyValueList.clear();
-            mPropertyBytes = null;
-        }
-    }
-
-    private String mFamilyName;
-    private String mGivenName;
-    private String mMiddleName;
-    private String mPrefix;
-    private String mSuffix;
-
-    // Used only when no family nor given name is found.
-    private String mFormattedName;
-
-    private String mPhoneticFamilyName;
-    private String mPhoneticGivenName;
-    private String mPhoneticMiddleName;
-
-    private String mPhoneticFullName;
-
-    private List<String> mNickNameList;
-
-    private String mDisplayName;
-
-    private String mBirthday;
-
-    private List<String> mNoteList;
-    private List<PhoneData> mPhoneList;
-    private List<EmailData> mEmailList;
-    private List<PostalData> mPostalList;
-    private List<OrganizationData> mOrganizationList;
-    private List<ImData> mImList;
-    private List<PhotoData> mPhotoList;
-    private List<String> mWebsiteList;
-    private List<List<String>> mAndroidCustomPropertyList;
-
-    private final int mVCardType;
-    private final Account mAccount;
-
-    public VCardEntry() {
-        this(VCardConfig.VCARD_TYPE_V21_GENERIC);
-    }
-
-    public VCardEntry(int vcardType) {
-        this(vcardType, null);
-    }
-
-    public VCardEntry(int vcardType, Account account) {
-        mVCardType = vcardType;
-        mAccount = account;
-    }
-
-    private void addPhone(int type, String data, String label, boolean isPrimary) {
-        if (mPhoneList == null) {
-            mPhoneList = new ArrayList<PhoneData>();
-        }
-        final StringBuilder builder = new StringBuilder();
-        final String trimed = data.trim();
-        final String formattedNumber;
-        if (type == Phone.TYPE_PAGER || VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
-            formattedNumber = trimed;
-        } else {
-            final int length = trimed.length();
-            for (int i = 0; i < length; i++) {
-                char ch = trimed.charAt(i);
-                if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
-                    builder.append(ch);
-                }
-            }
-
-            final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType);
-            formattedNumber = PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
-        }
-        PhoneData phoneData = new PhoneData(type, formattedNumber, label, isPrimary);
-        mPhoneList.add(phoneData);
-    }
-
-    private void addNickName(final String nickName) {
-        if (mNickNameList == null) {
-            mNickNameList = new ArrayList<String>();
-        }
-        mNickNameList.add(nickName);
-    }
-
-    private void addEmail(int type, String data, String label, boolean isPrimary){
-        if (mEmailList == null) {
-            mEmailList = new ArrayList<EmailData>();
-        }
-        mEmailList.add(new EmailData(type, data, label, isPrimary));
-    }
-
-    private void addPostal(int type, List<String> propValueList, String label, boolean isPrimary){
-        if (mPostalList == null) {
-            mPostalList = new ArrayList<PostalData>(0);
-        }
-        mPostalList.add(new PostalData(type, propValueList, label, isPrimary));
-    }
-
-    /**
-     * Should be called via {@link #handleOrgValue(int, List, boolean)} or
-     * {@link #handleTitleValue(String)}.
-     */
-    private void addNewOrganization(int type, final String companyName,
-            final String departmentName,
-            final String titleName, boolean isPrimary) {
-        if (mOrganizationList == null) {
-            mOrganizationList = new ArrayList<OrganizationData>();
-        }
-        mOrganizationList.add(new OrganizationData(type, companyName,
-                departmentName, titleName, isPrimary));
-    }
-
-    private static final List<String> sEmptyList =
-            Collections.unmodifiableList(new ArrayList<String>(0));
-
-    /**
-     * Set "ORG" related values to the appropriate data. If there's more than one
-     * {@link OrganizationData} objects, this input data are attached to the last one which
-     * does not have valid values (not including empty but only null). If there's no
-     * {@link OrganizationData} object, a new {@link OrganizationData} is created,
-     * whose title is set to null.
-     */
-    private void handleOrgValue(final int type, List<String> orgList, boolean isPrimary) {
-        if (orgList == null) {
-            orgList = sEmptyList;
-        }
-        final String companyName;
-        final String departmentName;
-        final int size = orgList.size();
-        switch (size) {
-            case 0: {
-                companyName = "";
-                departmentName = null;
-                break;
-            }
-            case 1: {
-                companyName = orgList.get(0);
-                departmentName = null;
-                break;
-            }
-            default: {  // More than 1.
-                companyName = orgList.get(0);
-                // We're not sure which is the correct string for department.
-                // In order to keep all the data, concatinate the rest of elements.
-                StringBuilder builder = new StringBuilder();
-                for (int i = 1; i < size; i++) {
-                    if (i > 1) {
-                        builder.append(' ');
-                    }
-                    builder.append(orgList.get(i));
-                }
-                departmentName = builder.toString();
-            }
-        }
-        if (mOrganizationList == null) {
-            // Create new first organization entry, with "null" title which may be
-            // added via handleTitleValue().
-            addNewOrganization(type, companyName, departmentName, null, isPrimary);
-            return;
-        }
-        for (OrganizationData organizationData : mOrganizationList) {
-            // Not use TextUtils.isEmpty() since ORG was set but the elements might be empty.
-            // e.g. "ORG;PREF:;" -> Both companyName and departmentName become empty but not null.
-            if (organizationData.companyName == null &&
-                    organizationData.departmentName == null) {
-                // Probably the "TITLE" property comes before the "ORG" property via
-                // handleTitleLine().
-                organizationData.companyName = companyName;
-                organizationData.departmentName = departmentName;
-                organizationData.isPrimary = isPrimary;
-                return;
-            }
-        }
-        // No OrganizatioData is available. Create another one, with "null" title, which may be
-        // added via handleTitleValue().
-        addNewOrganization(type, companyName, departmentName, null, isPrimary);
-    }
-
-    /**
-     * Set "title" value to the appropriate data. If there's more than one
-     * OrganizationData objects, this input is attached to the last one which does not
-     * have valid title value (not including empty but only null). If there's no
-     * OrganizationData object, a new OrganizationData is created, whose company name is
-     * set to null.
-     */
-    private void handleTitleValue(final String title) {
-        if (mOrganizationList == null) {
-            // Create new first organization entry, with "null" other info, which may be
-            // added via handleOrgValue().
-            addNewOrganization(DEFAULT_ORGANIZATION_TYPE, null, null, title, false);
-            return;
-        }
-        for (OrganizationData organizationData : mOrganizationList) {
-            if (organizationData.titleName == null) {
-                organizationData.titleName = title;
-                return;
-            }
-        }
-        // No Organization is available. Create another one, with "null" other info, which may be
-        // added via handleOrgValue().
-        addNewOrganization(DEFAULT_ORGANIZATION_TYPE, null, null, title, false);
-    }
-
-    private void addIm(int protocol, String customProtocol, int type,
-            String propValue, boolean isPrimary) {
-        if (mImList == null) {
-            mImList = new ArrayList<ImData>();
-        }
-        mImList.add(new ImData(protocol, customProtocol, type, propValue, isPrimary));
-    }
-
-    private void addNote(final String note) {
-        if (mNoteList == null) {
-            mNoteList = new ArrayList<String>(1);
-        }
-        mNoteList.add(note);
-    }
-
-    private void addPhotoBytes(String formatName, byte[] photoBytes, boolean isPrimary) {
-        if (mPhotoList == null) {
-            mPhotoList = new ArrayList<PhotoData>(1);
-        }
-        final PhotoData photoData = new PhotoData(0, null, photoBytes, isPrimary);
-        mPhotoList.add(photoData);
-    }
-
-    @SuppressWarnings("fallthrough")
-    private void handleNProperty(List<String> elems) {
-        // Family, Given, Middle, Prefix, Suffix. (1 - 5)
-        int size;
-        if (elems == null || (size = elems.size()) < 1) {
-            return;
-        }
-        if (size > 5) {
-            size = 5;
-        }
-
-        switch (size) {
-            // fallthrough
-            case 5: mSuffix = elems.get(4);
-            case 4: mPrefix = elems.get(3);
-            case 3: mMiddleName = elems.get(2);
-            case 2: mGivenName = elems.get(1);
-            default: mFamilyName = elems.get(0);
-        }
-    }
-
-    /**
-     * Note: Some Japanese mobile phones use this field for phonetic name,
-     *       since vCard 2.1 does not have "SORT-STRING" type.
-     *       Also, in some cases, the field has some ';'s in it.
-     *       Assume the ';' means the same meaning in N property
-     */
-    @SuppressWarnings("fallthrough")
-    private void handlePhoneticNameFromSound(List<String> elems) {
-        if (!(TextUtils.isEmpty(mPhoneticFamilyName) &&
-                TextUtils.isEmpty(mPhoneticMiddleName) &&
-                TextUtils.isEmpty(mPhoneticGivenName))) {
-            // This means the other properties like "X-PHONETIC-FIRST-NAME" was already found.
-            // Ignore "SOUND;X-IRMC-N".
-            return;
-        }
-
-        int size;
-        if (elems == null || (size = elems.size()) < 1) {
-            return;
-        }
-
-        // Assume that the order is "Family, Given, Middle".
-        // This is not from specification but mere assumption. Some Japanese phones use this order.
-        if (size > 3) {
-            size = 3;
-        }
-
-        if (elems.get(0).length() > 0) {
-            boolean onlyFirstElemIsNonEmpty = true;
-            for (int i = 1; i < size; i++) {
-                if (elems.get(i).length() > 0) {
-                    onlyFirstElemIsNonEmpty = false;
-                    break;
-                }
-            }
-            if (onlyFirstElemIsNonEmpty) {
-                final String[] namesArray = elems.get(0).split(" ");
-                final int nameArrayLength = namesArray.length;
-                if (nameArrayLength == 3) {
-                    // Assume the string is "Family Middle Given".
-                    mPhoneticFamilyName = namesArray[0];
-                    mPhoneticMiddleName = namesArray[1];
-                    mPhoneticGivenName = namesArray[2];
-                } else if (nameArrayLength == 2) {
-                    // Assume the string is "Family Given" based on the Japanese mobile
-                    // phones' preference.
-                    mPhoneticFamilyName = namesArray[0];
-                    mPhoneticGivenName = namesArray[1];
-                } else {
-                    mPhoneticFullName = elems.get(0);
-                }
-                return;
-            }
-        }
-
-        switch (size) {
-            // fallthrough
-            case 3: mPhoneticMiddleName = elems.get(2);
-            case 2: mPhoneticGivenName = elems.get(1);
-            default: mPhoneticFamilyName = elems.get(0);
-        }
-    }
-
-    public void addProperty(final Property property) {
-        final String propName = property.mPropertyName;
-        final Map<String, Collection<String>> paramMap = property.mParameterMap;
-        final List<String> propValueList = property.mPropertyValueList;
-        byte[] propBytes = property.mPropertyBytes;
-
-        if (propValueList.size() == 0) {
-            return;
-        }
-        final String propValue = listToString(propValueList).trim();
-
-        if (propName.equals(VCardConstants.PROPERTY_VERSION)) {
-            // vCard version. Ignore this.
-        } else if (propName.equals(VCardConstants.PROPERTY_FN)) {
-            mFormattedName = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_NAME) && mFormattedName == null) {
-            // Only in vCard 3.0. Use this if FN, which must exist in vCard 3.0 but may not
-            // actually exist in the real vCard data, does not exist.
-            mFormattedName = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_N)) {
-            handleNProperty(propValueList);
-        } else if (propName.equals(VCardConstants.PROPERTY_SORT_STRING)) {
-            mPhoneticFullName = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_NICKNAME) ||
-                propName.equals(VCardConstants.ImportOnly.PROPERTY_X_NICKNAME)) {
-            addNickName(propValue);
-        } else if (propName.equals(VCardConstants.PROPERTY_SOUND)) {
-            Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            if (typeCollection != null
-                    && typeCollection.contains(VCardConstants.PARAM_TYPE_X_IRMC_N)) {
-                // As of 2009-10-08, Parser side does not split a property value into separated
-                // values using ';' (in other words, propValueList.size() == 1),
-                // which is correct behavior from the view of vCard 2.1.
-                // But we want it to be separated, so do the separation here.
-                final List<String> phoneticNameList =
-                        VCardUtils.constructListFromValue(propValue,
-                                VCardConfig.isV30(mVCardType));
-                handlePhoneticNameFromSound(phoneticNameList);
-            } else {
-                // Ignore this field since Android cannot understand what it is.
-            }
-        } else if (propName.equals(VCardConstants.PROPERTY_ADR)) {
-            boolean valuesAreAllEmpty = true;
-            for (String value : propValueList) {
-                if (value.length() > 0) {
-                    valuesAreAllEmpty = false;
-                    break;
-                }
-            }
-            if (valuesAreAllEmpty) {
-                return;
-            }
-
-            int type = -1;
-            String label = "";
-            boolean isPrimary = false;
-            Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            if (typeCollection != null) {
-                for (String typeString : typeCollection) {
-                    typeString = typeString.toUpperCase();
-                    if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
-                        isPrimary = true;
-                    } else if (typeString.equals(VCardConstants.PARAM_TYPE_HOME)) {
-                        type = StructuredPostal.TYPE_HOME;
-                        label = "";
-                    } else if (typeString.equals(VCardConstants.PARAM_TYPE_WORK) ||
-                            typeString.equalsIgnoreCase(VCardConstants.PARAM_EXTRA_TYPE_COMPANY)) {
-                        // "COMPANY" seems emitted by Windows Mobile, which is not
-                        // specifically supported by vCard 2.1. We assume this is same
-                        // as "WORK".
-                        type = StructuredPostal.TYPE_WORK;
-                        label = "";
-                    } else if (typeString.equals(VCardConstants.PARAM_ADR_TYPE_PARCEL) ||
-                            typeString.equals(VCardConstants.PARAM_ADR_TYPE_DOM) ||
-                            typeString.equals(VCardConstants.PARAM_ADR_TYPE_INTL)) {
-                        // We do not have any appropriate way to store this information.
-                    } else {
-                        if (typeString.startsWith("X-") && type < 0) {
-                            typeString = typeString.substring(2);
-                        }
-                        // vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
-                        // emit non-standard types. We do not handle their values now.
-                        type = StructuredPostal.TYPE_CUSTOM;
-                        label = typeString;
-                    }
-                }
-            }
-            // We use "HOME" as default
-            if (type < 0) {
-                type = StructuredPostal.TYPE_HOME;
-            }
-
-            addPostal(type, propValueList, label, isPrimary);
-        } else if (propName.equals(VCardConstants.PROPERTY_EMAIL)) {
-            int type = -1;
-            String label = null;
-            boolean isPrimary = false;
-            Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            if (typeCollection != null) {
-                for (String typeString : typeCollection) {
-                    typeString = typeString.toUpperCase();
-                    if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
-                        isPrimary = true;
-                    } else if (typeString.equals(VCardConstants.PARAM_TYPE_HOME)) {
-                        type = Email.TYPE_HOME;
-                    } else if (typeString.equals(VCardConstants.PARAM_TYPE_WORK)) {
-                        type = Email.TYPE_WORK;
-                    } else if (typeString.equals(VCardConstants.PARAM_TYPE_CELL)) {
-                        type = Email.TYPE_MOBILE;
-                    } else {
-                        if (typeString.startsWith("X-") && type < 0) {
-                            typeString = typeString.substring(2);
-                        }
-                        // vCard 3.0 allows iana-token.
-                        // We may have INTERNET (specified in vCard spec),
-                        // SCHOOL, etc.
-                        type = Email.TYPE_CUSTOM;
-                        label = typeString;
-                    }
-                }
-            }
-            if (type < 0) {
-                type = Email.TYPE_OTHER;
-            }
-            addEmail(type, propValue, label, isPrimary);
-        } else if (propName.equals(VCardConstants.PROPERTY_ORG)) {
-            // vCard specification does not specify other types.
-            final int type = Organization.TYPE_WORK;
-            boolean isPrimary = false;
-            Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            if (typeCollection != null) {
-                for (String typeString : typeCollection) {
-                    if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
-                        isPrimary = true;
-                    }
-                }
-            }
-            handleOrgValue(type, propValueList, isPrimary);
-        } else if (propName.equals(VCardConstants.PROPERTY_TITLE)) {
-            handleTitleValue(propValue);
-        } else if (propName.equals(VCardConstants.PROPERTY_ROLE)) {
-            // This conflicts with TITLE. Ignore for now...
-            // handleTitleValue(propValue);
-        } else if (propName.equals(VCardConstants.PROPERTY_PHOTO) ||
-                propName.equals(VCardConstants.PROPERTY_LOGO)) {
-            Collection<String> paramMapValue = paramMap.get("VALUE");
-            if (paramMapValue != null && paramMapValue.contains("URL")) {
-                // Currently we do not have appropriate example for testing this case.
-            } else {
-                final Collection<String> typeCollection = paramMap.get("TYPE");
-                String formatName = null;
-                boolean isPrimary = false;
-                if (typeCollection != null) {
-                    for (String typeValue : typeCollection) {
-                        if (VCardConstants.PARAM_TYPE_PREF.equals(typeValue)) {
-                            isPrimary = true;
-                        } else if (formatName == null){
-                            formatName = typeValue;
-                        }
-                    }
-                }
-                addPhotoBytes(formatName, propBytes, isPrimary);
-            }
-        } else if (propName.equals(VCardConstants.PROPERTY_TEL)) {
-            final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            final Object typeObject =
-                VCardUtils.getPhoneTypeFromStrings(typeCollection, propValue);
-            final int type;
-            final String label;
-            if (typeObject instanceof Integer) {
-                type = (Integer)typeObject;
-                label = null;
-            } else {
-                type = Phone.TYPE_CUSTOM;
-                label = typeObject.toString();
-            }
-
-            final boolean isPrimary;
-            if (typeCollection != null && typeCollection.contains(VCardConstants.PARAM_TYPE_PREF)) {
-                isPrimary = true;
-            } else {
-                isPrimary = false;
-            }
-            addPhone(type, propValue, label, isPrimary);
-        } else if (propName.equals(VCardConstants.PROPERTY_X_SKYPE_PSTNNUMBER)) {
-            // The phone number available via Skype.
-            Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            final int type = Phone.TYPE_OTHER;
-            final boolean isPrimary;
-            if (typeCollection != null && typeCollection.contains(VCardConstants.PARAM_TYPE_PREF)) {
-                isPrimary = true;
-            } else {
-                isPrimary = false;
-            }
-            addPhone(type, propValue, null, isPrimary);
-        } else if (sImMap.containsKey(propName)) {
-            final int protocol = sImMap.get(propName);
-            boolean isPrimary = false;
-            int type = -1;
-            final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
-            if (typeCollection != null) {
-                for (String typeString : typeCollection) {
-                    if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
-                        isPrimary = true;
-                    } else if (type < 0) {
-                        if (typeString.equalsIgnoreCase(VCardConstants.PARAM_TYPE_HOME)) {
-                            type = Im.TYPE_HOME;
-                        } else if (typeString.equalsIgnoreCase(VCardConstants.PARAM_TYPE_WORK)) {
-                            type = Im.TYPE_WORK;
-                        }
-                    }
-                }
-            }
-            if (type < 0) {
-                type = Phone.TYPE_HOME;
-            }
-            addIm(protocol, null, type, propValue, isPrimary);
-        } else if (propName.equals(VCardConstants.PROPERTY_NOTE)) {
-            addNote(propValue);
-        } else if (propName.equals(VCardConstants.PROPERTY_URL)) {
-            if (mWebsiteList == null) {
-                mWebsiteList = new ArrayList<String>(1);
-            }
-            mWebsiteList.add(propValue);
-        } else if (propName.equals(VCardConstants.PROPERTY_BDAY)) {
-            mBirthday = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_FIRST_NAME)) {
-            mPhoneticGivenName = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_MIDDLE_NAME)) {
-            mPhoneticMiddleName = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME)) {
-            mPhoneticFamilyName = propValue;
-        } else if (propName.equals(VCardConstants.PROPERTY_X_ANDROID_CUSTOM)) {
-            final List<String> customPropertyList =
-                VCardUtils.constructListFromValue(propValue,
-                        VCardConfig.isV30(mVCardType));
-            handleAndroidCustomProperty(customPropertyList);
-        /*} else if (propName.equals("REV")) {
-            // Revision of this VCard entry. I think we can ignore this.
-        } else if (propName.equals("UID")) {
-        } else if (propName.equals("KEY")) {
-            // Type is X509 or PGP? I don't know how to handle this...
-        } else if (propName.equals("MAILER")) {
-        } else if (propName.equals("TZ")) {
-        } else if (propName.equals("GEO")) {
-        } else if (propName.equals("CLASS")) {
-            // vCard 3.0 only.
-            // e.g. CLASS:CONFIDENTIAL
-        } else if (propName.equals("PROFILE")) {
-            // VCard 3.0 only. Must be "VCARD". I think we can ignore this.
-        } else if (propName.equals("CATEGORIES")) {
-            // VCard 3.0 only.
-            // e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY
-        } else if (propName.equals("SOURCE")) {
-            // VCard 3.0 only.
-        } else if (propName.equals("PRODID")) {
-            // VCard 3.0 only.
-            // To specify the identifier for the product that created
-            // the vCard object.*/
-        } else {
-            // Unknown X- words and IANA token.
-        }
-    }
-
-    private void handleAndroidCustomProperty(final List<String> customPropertyList) {
-        if (mAndroidCustomPropertyList == null) {
-            mAndroidCustomPropertyList = new ArrayList<List<String>>();
-        }
-        mAndroidCustomPropertyList.add(customPropertyList);
-    }
-
-    /**
-     * Construct the display name. The constructed data must not be null.
-     */
-    private void constructDisplayName() {
-        // FullName (created via "FN" or "NAME" field) is prefered.
-        if (!TextUtils.isEmpty(mFormattedName)) {
-            mDisplayName = mFormattedName;
-        } else if (!(TextUtils.isEmpty(mFamilyName) && TextUtils.isEmpty(mGivenName))) {
-            mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
-                    mFamilyName, mMiddleName, mGivenName, mPrefix, mSuffix);
-        } else if (!(TextUtils.isEmpty(mPhoneticFamilyName) &&
-                TextUtils.isEmpty(mPhoneticGivenName))) {
-            mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
-                    mPhoneticFamilyName, mPhoneticMiddleName, mPhoneticGivenName);
-        } else if (mEmailList != null && mEmailList.size() > 0) {
-            mDisplayName = mEmailList.get(0).data;
-        } else if (mPhoneList != null && mPhoneList.size() > 0) {
-            mDisplayName = mPhoneList.get(0).data;
-        } else if (mPostalList != null && mPostalList.size() > 0) {
-            mDisplayName = mPostalList.get(0).getFormattedAddress(mVCardType);
-        } else if (mOrganizationList != null && mOrganizationList.size() > 0) {
-            mDisplayName = mOrganizationList.get(0).getFormattedString();
-        }
-
-        if (mDisplayName == null) {
-            mDisplayName = "";
-        }
-    }
-
-    /**
-     * Consolidate several fielsds (like mName) using name candidates,
-     */
-    public void consolidateFields() {
-        constructDisplayName();
-
-        if (mPhoneticFullName != null) {
-            mPhoneticFullName = mPhoneticFullName.trim();
-        }
-    }
-
-    public Uri pushIntoContentResolver(ContentResolver resolver) {
-        ArrayList<ContentProviderOperation> operationList =
-            new ArrayList<ContentProviderOperation>();
-        // After applying the batch the first result's Uri is returned so it is important that
-        // the RawContact is the first operation that gets inserted into the list
-        ContentProviderOperation.Builder builder =
-            ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
-        String myGroupsId = null;
-        if (mAccount != null) {
-            builder.withValue(RawContacts.ACCOUNT_NAME, mAccount.name);
-            builder.withValue(RawContacts.ACCOUNT_TYPE, mAccount.type);
-        } else {
-            builder.withValue(RawContacts.ACCOUNT_NAME, null);
-            builder.withValue(RawContacts.ACCOUNT_TYPE, null);
-        }
-        operationList.add(builder.build());
-
-        if (!nameFieldsAreEmpty()) {
-            builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-            builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
-            builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
-
-            builder.withValue(StructuredName.GIVEN_NAME, mGivenName);
-            builder.withValue(StructuredName.FAMILY_NAME, mFamilyName);
-            builder.withValue(StructuredName.MIDDLE_NAME, mMiddleName);
-            builder.withValue(StructuredName.PREFIX, mPrefix);
-            builder.withValue(StructuredName.SUFFIX, mSuffix);
-
-            if (!(TextUtils.isEmpty(mPhoneticGivenName)
-                    && TextUtils.isEmpty(mPhoneticFamilyName)
-                    && TextUtils.isEmpty(mPhoneticMiddleName))) {
-                builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticGivenName);
-                builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, mPhoneticFamilyName);
-                builder.withValue(StructuredName.PHONETIC_MIDDLE_NAME, mPhoneticMiddleName);
-            } else if (!TextUtils.isEmpty(mPhoneticFullName)) {
-                builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticFullName);
-            }
-
-            builder.withValue(StructuredName.DISPLAY_NAME, getDisplayName());
-            operationList.add(builder.build());
-        }
-
-        if (mNickNameList != null && mNickNameList.size() > 0) {
-            for (String nickName : mNickNameList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Nickname.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
-                builder.withValue(Nickname.TYPE, Nickname.TYPE_DEFAULT);
-                builder.withValue(Nickname.NAME, nickName);
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mPhoneList != null) {
-            for (PhoneData phoneData : mPhoneList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
-
-                builder.withValue(Phone.TYPE, phoneData.type);
-                if (phoneData.type == Phone.TYPE_CUSTOM) {
-                    builder.withValue(Phone.LABEL, phoneData.label);
-                }
-                builder.withValue(Phone.NUMBER, phoneData.data);
-                if (phoneData.isPrimary) {
-                    builder.withValue(Phone.IS_PRIMARY, 1);
-                }
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mOrganizationList != null) {
-            for (OrganizationData organizationData : mOrganizationList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Organization.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
-                builder.withValue(Organization.TYPE, organizationData.type);
-                if (organizationData.companyName != null) {
-                    builder.withValue(Organization.COMPANY, organizationData.companyName);
-                }
-                if (organizationData.departmentName != null) {
-                    builder.withValue(Organization.DEPARTMENT, organizationData.departmentName);
-                }
-                if (organizationData.titleName != null) {
-                    builder.withValue(Organization.TITLE, organizationData.titleName);
-                }
-                if (organizationData.isPrimary) {
-                    builder.withValue(Organization.IS_PRIMARY, 1);
-                }
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mEmailList != null) {
-            for (EmailData emailData : mEmailList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
-
-                builder.withValue(Email.TYPE, emailData.type);
-                if (emailData.type == Email.TYPE_CUSTOM) {
-                    builder.withValue(Email.LABEL, emailData.label);
-                }
-                builder.withValue(Email.DATA, emailData.data);
-                if (emailData.isPrimary) {
-                    builder.withValue(Data.IS_PRIMARY, 1);
-                }
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mPostalList != null) {
-            for (PostalData postalData : mPostalList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                VCardUtils.insertStructuredPostalDataUsingContactsStruct(
-                        mVCardType, builder, postalData);
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mImList != null) {
-            for (ImData imData : mImList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Im.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
-                builder.withValue(Im.TYPE, imData.type);
-                builder.withValue(Im.PROTOCOL, imData.protocol);
-                if (imData.protocol == Im.PROTOCOL_CUSTOM) {
-                    builder.withValue(Im.CUSTOM_PROTOCOL, imData.customProtocol);
-                }
-                if (imData.isPrimary) {
-                    builder.withValue(Data.IS_PRIMARY, 1);
-                }
-            }
-        }
-
-        if (mNoteList != null) {
-            for (String note : mNoteList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Note.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
-                builder.withValue(Note.NOTE, note);
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mPhotoList != null) {
-            for (PhotoData photoData : mPhotoList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Photo.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
-                builder.withValue(Photo.PHOTO, photoData.photoBytes);
-                if (photoData.isPrimary) {
-                    builder.withValue(Photo.IS_PRIMARY, 1);
-                }
-                operationList.add(builder.build());
-            }
-        }
-
-        if (mWebsiteList != null) {
-            for (String website : mWebsiteList) {
-                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                builder.withValueBackReference(Website.RAW_CONTACT_ID, 0);
-                builder.withValue(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
-                builder.withValue(Website.URL, website);
-                // There's no information about the type of URL in vCard.
-                // We use TYPE_HOMEPAGE for safety.
-                builder.withValue(Website.TYPE, Website.TYPE_HOMEPAGE);
-                operationList.add(builder.build());
-            }
-        }
-
-        if (!TextUtils.isEmpty(mBirthday)) {
-            builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-            builder.withValueBackReference(Event.RAW_CONTACT_ID, 0);
-            builder.withValue(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
-            builder.withValue(Event.START_DATE, mBirthday);
-            builder.withValue(Event.TYPE, Event.TYPE_BIRTHDAY);
-            operationList.add(builder.build());
-        }
-
-        if (mAndroidCustomPropertyList != null) {
-            for (List<String> customPropertyList : mAndroidCustomPropertyList) {
-                int size = customPropertyList.size();
-                if (size < 2 || TextUtils.isEmpty(customPropertyList.get(0))) {
-                    continue;
-                } else if (size > VCardConstants.MAX_DATA_COLUMN + 1) {
-                    size = VCardConstants.MAX_DATA_COLUMN + 1;
-                    customPropertyList =
-                        customPropertyList.subList(0, VCardConstants.MAX_DATA_COLUMN + 2);
-                }
-
-                int i = 0;
-                for (final String customPropertyValue : customPropertyList) {
-                    if (i == 0) {
-                        final String mimeType = customPropertyValue;
-                        builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-                        builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
-                        builder.withValue(Data.MIMETYPE, mimeType);
-                    } else {  // 1 <= i && i <= MAX_DATA_COLUMNS
-                        if (!TextUtils.isEmpty(customPropertyValue)) {
-                            builder.withValue("data" + i, customPropertyValue);
-                        }
-                    }
-
-                    i++;
-                }
-                operationList.add(builder.build());
-            }
-        }
-
-        if (myGroupsId != null) {
-            builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-            builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
-            builder.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
-            builder.withValue(GroupMembership.GROUP_SOURCE_ID, myGroupsId);
-            operationList.add(builder.build());
-        }
-
-        try {
-            ContentProviderResult[] results = resolver.applyBatch(
-                        ContactsContract.AUTHORITY, operationList);
-            // the first result is always the raw_contact. return it's uri so
-            // that it can be found later. do null checking for badly behaving
-            // ContentResolvers
-            return (results == null || results.length == 0 || results[0] == null)
-                ? null
-                : results[0].uri;
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
-            return null;
-        } catch (OperationApplicationException e) {
-            Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
-            return null;
-        }
-    }
-
-    public static VCardEntry buildFromResolver(ContentResolver resolver) {
-        return buildFromResolver(resolver, Contacts.CONTENT_URI);
-    }
-
-    public static VCardEntry buildFromResolver(ContentResolver resolver, Uri uri) {
-
-        return null;
-    }
-
-    private boolean nameFieldsAreEmpty() {
-        return (TextUtils.isEmpty(mFamilyName)
-                && TextUtils.isEmpty(mMiddleName)
-                && TextUtils.isEmpty(mGivenName)
-                && TextUtils.isEmpty(mPrefix)
-                && TextUtils.isEmpty(mSuffix)
-                && TextUtils.isEmpty(mFormattedName)
-                && TextUtils.isEmpty(mPhoneticFamilyName)
-                && TextUtils.isEmpty(mPhoneticMiddleName)
-                && TextUtils.isEmpty(mPhoneticGivenName)
-                && TextUtils.isEmpty(mPhoneticFullName));
-    }
-
-    public boolean isIgnorable() {
-        return getDisplayName().length() == 0;
-    }
-
-    private String listToString(List<String> list){
-        final int size = list.size();
-        if (size > 1) {
-            StringBuilder builder = new StringBuilder();
-            int i = 0;
-            for (String type : list) {
-                builder.append(type);
-                if (i < size - 1) {
-                    builder.append(";");
-                }
-            }
-            return builder.toString();
-        } else if (size == 1) {
-            return list.get(0);
-        } else {
-            return "";
-        }
-    }
-
-    // All getter methods should be used carefully, since they may change
-    // in the future as of 2009-10-05, on which I cannot be sure this structure
-    // is completely consolidated.
-    //
-    // Also note that these getter methods should be used only after
-    // all properties being pushed into this object. If not, incorrect
-    // value will "be stored in the local cache and" be returned to you.
-
-    public String getFamilyName() {
-        return mFamilyName;
-    }
-
-    public String getGivenName() {
-        return mGivenName;
-    }
-
-    public String getMiddleName() {
-        return mMiddleName;
-    }
-
-    public String getPrefix() {
-        return mPrefix;
-    }
-
-    public String getSuffix() {
-        return mSuffix;
-    }
-
-    public String getFullName() {
-        return mFormattedName;
-    }
-
-    public String getPhoneticFamilyName() {
-        return mPhoneticFamilyName;
-    }
-
-    public String getPhoneticGivenName() {
-        return mPhoneticGivenName;
-    }
-
-    public String getPhoneticMiddleName() {
-        return mPhoneticMiddleName;
-    }
-
-    public String getPhoneticFullName() {
-        return mPhoneticFullName;
-    }
-
-    public final List<String> getNickNameList() {
-        return mNickNameList;
-    }
-
-    public String getBirthday() {
-        return mBirthday;
-    }
-
-    public final List<String> getNotes() {
-        return mNoteList;
-    }
-
-    public final List<PhoneData> getPhoneList() {
-        return mPhoneList;
-    }
-
-    public final List<EmailData> getEmailList() {
-        return mEmailList;
-    }
-
-    public final List<PostalData> getPostalList() {
-        return mPostalList;
-    }
-
-    public final List<OrganizationData> getOrganizationList() {
-        return mOrganizationList;
-    }
-
-    public final List<ImData> getImList() {
-        return mImList;
-    }
-
-    public final List<PhotoData> getPhotoList() {
-        return mPhotoList;
-    }
-
-    public final List<String> getWebsiteList() {
-        return mWebsiteList;
-    }
-
-    public String getDisplayName() {
-        if (mDisplayName == null) {
-            constructDisplayName();
-        }
-        return mDisplayName;
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardEntryCommitter.java b/vcard/java/com/android/vcard/VCardEntryCommitter.java
deleted file mode 100644
index 7bd314e..0000000
--- a/vcard/java/com/android/vcard/VCardEntryCommitter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * <P>
- * {@link VCardEntryHandler} implementation which commits the entry to ContentResolver.
- * </P>
- * <P>
- * Note:<BR />
- * Each vCard may contain big photo images encoded by BASE64,
- * If we store all vCard entries in memory, OutOfMemoryError may be thrown.
- * Thus, this class push each VCard entry into ContentResolver immediately.
- * </P>
- */
-public class VCardEntryCommitter implements VCardEntryHandler {
-    public static String LOG_TAG = "VCardEntryComitter";
-
-    private final ContentResolver mContentResolver;
-    private long mTimeToCommit;
-    private ArrayList<Uri> mCreatedUris = new ArrayList<Uri>();
-
-    public VCardEntryCommitter(ContentResolver resolver) {
-        mContentResolver = resolver;
-    }
-
-    public void onStart() {
-    }
-
-    public void onEnd() {
-        if (VCardConfig.showPerformanceLog()) {
-            Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
-        }
-    }
-
-    public void onEntryCreated(final VCardEntry vcardEntry) {
-        long start = System.currentTimeMillis();
-        mCreatedUris.add(vcardEntry.pushIntoContentResolver(mContentResolver));
-        mTimeToCommit += System.currentTimeMillis() - start;
-    }
-
-    /**
-     * Returns the list of created Uris. This list should not be modified by the caller as it is
-     * not a clone.
-     */
-   public ArrayList<Uri> getCreatedUris() {
-        return mCreatedUris;
-    }
-}
\ No newline at end of file
diff --git a/vcard/java/com/android/vcard/VCardEntryConstructor.java b/vcard/java/com/android/vcard/VCardEntryConstructor.java
deleted file mode 100644
index 6cee070..0000000
--- a/vcard/java/com/android/vcard/VCardEntryConstructor.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.accounts.Account;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * <p>
- * The {@link VCardInterpreter} implementation which enables {@link VCardEntryHandler} objects
- * to easily handle each vCard entry.
- * </p>
- * <p>
- * This class understand details inside vCard and translates it to {@link VCardEntry}.
- * Then the class throw it to {@link VCardEntryHandler} registered via
- * {@link #addEntryHandler(VCardEntryHandler)}, so that all those registered objects
- * are able to handle the {@link VCardEntry} object.
- * </p>
- * <p>
- * If you want to know the detail inside vCard, it would be better to implement
- * {@link VCardInterpreter} directly, instead of relying on this class and
- * {@link VCardEntry} created by the object.
- * </p>
- */
-public class VCardEntryConstructor implements VCardInterpreter {
-    private static String LOG_TAG = "VCardEntryConstructor";
-
-    private VCardEntry.Property mCurrentProperty = new VCardEntry.Property();
-    private VCardEntry mCurrentVCardEntry;
-    private String mParamType;
-    
-    // The charset using which {@link VCardInterpreter} parses the text.
-    // Each String is first decoded into binary stream with this charset, and encoded back
-    // to "target charset", which may be explicitly specified by the vCard with "CHARSET"
-    // property or implicitly mentioned by its version (e.g. vCard 3.0 recommends UTF-8).
-    private final String mSourceCharset;
-
-    private final boolean mStrictLineBreaking;
-    private final int mVCardType;
-    private final Account mAccount;
-    
-    // For measuring performance.
-    private long mTimePushIntoContentResolver;
-
-    private final List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
-
-    public VCardEntryConstructor() {
-        this(VCardConfig.VCARD_TYPE_V21_GENERIC, null);
-    }
-
-    public VCardEntryConstructor(final int vcardType) {
-        this(vcardType, null, null, false);
-    }
-
-    public VCardEntryConstructor(final int vcardType, final Account account) {
-        this(vcardType, account, null, false);
-    }
-
-    public VCardEntryConstructor(final int vcardType, final Account account,
-            final String inputCharset) {
-        this(vcardType, account, inputCharset, false);
-    }
-
-    /**
-     * @hide Just for testing.
-     */
-    public VCardEntryConstructor(final int vcardType, final Account account,
-            final String inputCharset, final boolean strictLineBreakParsing) {
-        if (inputCharset != null) {
-            mSourceCharset = inputCharset;
-        } else {
-            mSourceCharset = VCardConfig.DEFAULT_INTERMEDIATE_CHARSET;
-        }
-        mStrictLineBreaking = strictLineBreakParsing;
-        mVCardType = vcardType;
-        mAccount = account;
-    }
-
-    public void addEntryHandler(VCardEntryHandler entryHandler) {
-        mEntryHandlers.add(entryHandler);
-    }
-    
-    public void start() {
-        for (VCardEntryHandler entryHandler : mEntryHandlers) {
-            entryHandler.onStart();
-        }
-    }
-
-    public void end() {
-        for (VCardEntryHandler entryHandler : mEntryHandlers) {
-            entryHandler.onEnd();
-        }
-    }
-
-    public void clear() {
-        mCurrentVCardEntry = null;
-        mCurrentProperty = new VCardEntry.Property();
-    }
-
-    public void startEntry() {
-        if (mCurrentVCardEntry != null) {
-            Log.e(LOG_TAG, "Nested VCard code is not supported now.");
-        }
-        mCurrentVCardEntry = new VCardEntry(mVCardType, mAccount);
-    }
-
-    public void endEntry() {
-        mCurrentVCardEntry.consolidateFields();
-        for (VCardEntryHandler entryHandler : mEntryHandlers) {
-            entryHandler.onEntryCreated(mCurrentVCardEntry);
-        }
-        mCurrentVCardEntry = null;
-    }
-
-    public void startProperty() {
-        mCurrentProperty.clear();
-    }
-
-    public void endProperty() {
-        mCurrentVCardEntry.addProperty(mCurrentProperty);
-    }
-    
-    public void propertyName(String name) {
-        mCurrentProperty.setPropertyName(name);
-    }
-
-    public void propertyGroup(String group) {
-    }
-
-    public void propertyParamType(String type) {
-        if (mParamType != null) {
-            Log.e(LOG_TAG, "propertyParamType() is called more than once " +
-                    "before propertyParamValue() is called");
-        }
-        mParamType = type;
-    }
-
-    public void propertyParamValue(String value) {
-        if (mParamType == null) {
-            // From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
-            mParamType = "TYPE";
-        }
-        mCurrentProperty.addParameter(mParamType, value);
-        mParamType = null;
-    }
-
-    private static String encodeToSystemCharset(String originalString,
-            String sourceCharset, String targetCharset) {
-        if (sourceCharset.equalsIgnoreCase(targetCharset)) {
-            return originalString;
-        }
-        final Charset charset = Charset.forName(sourceCharset);
-        final ByteBuffer byteBuffer = charset.encode(originalString);
-        // byteBuffer.array() "may" return byte array which is larger than
-        // byteBuffer.remaining(). Here, we keep on the safe side.
-        final byte[] bytes = new byte[byteBuffer.remaining()];
-        byteBuffer.get(bytes);
-        try {
-            String ret = new String(bytes, targetCharset);
-            return ret;
-        } catch (UnsupportedEncodingException e) {
-            Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
-            return null;
-        }
-    }
-
-    private String handleOneValue(String value,
-            String sourceCharset, String targetCharset, String encoding) {
-        if (value == null) {
-            Log.w(LOG_TAG, "Null is given.");
-            value = "";
-        }
-
-        if (encoding != null) {
-            if (encoding.equals("BASE64") || encoding.equals("B")) {
-                mCurrentProperty.setPropertyBytes(Base64.decode(value.getBytes(), Base64.DEFAULT));
-                return value;
-            } else if (encoding.equals("QUOTED-PRINTABLE")) {
-                return VCardUtils.parseQuotedPrintable(
-                        value, mStrictLineBreaking, sourceCharset, targetCharset);
-            }
-            Log.w(LOG_TAG, "Unknown encoding. Fall back to default.");
-        }
-
-        // Just translate the charset of a given String from inputCharset to a system one. 
-        return encodeToSystemCharset(value, sourceCharset, targetCharset);
-    }
-    
-    public void propertyValues(List<String> values) {
-        if (values == null || values.isEmpty()) {
-            return;
-        }
-
-        final Collection<String> charsetCollection = mCurrentProperty.getParameters("CHARSET");
-        final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING");
-        final String encoding =
-            ((encodingCollection != null) ? encodingCollection.iterator().next() : null);
-        String targetCharset = CharsetUtils.nameForDefaultVendor(
-                ((charsetCollection != null) ? charsetCollection.iterator().next() : null));
-        if (TextUtils.isEmpty(targetCharset)) {
-            targetCharset = VCardConfig.DEFAULT_IMPORT_CHARSET;
-        }
-
-        for (final String value : values) {
-            mCurrentProperty.addToPropertyValueList(
-                    handleOneValue(value, mSourceCharset, targetCharset, encoding));
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void showPerformanceInfo() {
-        Log.d(LOG_TAG, "time for insert ContactStruct to database: " + 
-                mTimePushIntoContentResolver + " ms");
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardEntryCounter.java b/vcard/java/com/android/vcard/VCardEntryCounter.java
deleted file mode 100644
index 7bfe977..0000000
--- a/vcard/java/com/android/vcard/VCardEntryCounter.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import java.util.List;
-
-/**
- * The class which just counts the number of vCard entries in the specified input.
- */
-public class VCardEntryCounter implements VCardInterpreter {
-    private int mCount;
-
-    public int getCount() {
-        return mCount;
-    }
-
-    public void start() {
-    }
-
-    public void end() {
-    }
-
-    public void startEntry() {
-    }
-
-    public void endEntry() {
-        mCount++;
-    }
-
-    public void startProperty() {
-    }
-
-    public void endProperty() {
-    }
-
-    public void propertyGroup(String group) {
-    }
-
-    public void propertyName(String name) {
-    }
-
-    public void propertyParamType(String type) {
-    }
-
-    public void propertyParamValue(String value) {
-    }
-
-    public void propertyValues(List<String> values) {
-    }    
-}
diff --git a/vcard/java/com/android/vcard/VCardEntryHandler.java b/vcard/java/com/android/vcard/VCardEntryHandler.java
deleted file mode 100644
index ef35a20..0000000
--- a/vcard/java/com/android/vcard/VCardEntryHandler.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-/**
- * <p>
- * The interface called by {@link VCardEntryConstructor}.
- * </p>
- * <p>
- * This class is useful when you don't want to know vCard data in detail. If you want to know
- * it, it would be better to consider using {@link VCardInterpreter}.
- * </p>
- */
-public interface VCardEntryHandler {
-    /**
-     * Called when the parsing started.
-     */
-    public void onStart();
-
-    /**
-     * The method called when one VCard entry is successfully created
-     */
-    public void onEntryCreated(final VCardEntry entry);
-
-    /**
-     * Called when the parsing ended.
-     * Able to be use this method for showing performance log, etc.
-     */
-    public void onEnd();
-}
diff --git a/vcard/java/com/android/vcard/VCardInterpreter.java b/vcard/java/com/android/vcard/VCardInterpreter.java
deleted file mode 100644
index 2d98764..0000000
--- a/vcard/java/com/android/vcard/VCardInterpreter.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import java.util.List;
-
-/**
- * <P>
- * The interface which should be implemented by the classes which have to analyze each
- * vCard entry minutely.
- * </P>
- * <P>
- * Here, there are several terms specific to vCard (and this library).
- * </P>
- * <P>
- * The term "entry" is one vCard representation in the input, which should start with "BEGIN:VCARD"
- * and end with "END:VCARD".
- * </P>
- * <P>
- * The term "property" is one line in vCard entry, which consists of "group", "property name",
- * "parameter(param) names and values", and "property values".
- * </P>
- * <P>
- * e.g. group1.propName;paramName1=paramValue1;paramName2=paramValue2;propertyValue1;propertyValue2...
- * </P>
- */
-public interface VCardInterpreter {
-    /**
-     * Called when vCard interpretation started.
-     */
-    void start();
-
-    /**
-     * Called when vCard interpretation finished.
-     */
-    void end();
-
-    /** 
-     * Called when parsing one vCard entry started.
-     * More specifically, this method is called when "BEGIN:VCARD" is read.
-     */
-    void startEntry();
-
-    /**
-     * Called when parsing one vCard entry ended.
-     * More specifically, this method is called when "END:VCARD" is read.
-     * Note that {@link #startEntry()} may be called since
-     * vCard (especially 2.1) allows nested vCard.
-     */
-    void endEntry();
-
-    /**
-     * Called when reading one property started.
-     */
-    void startProperty();
-
-    /**
-     * Called when reading one property ended.
-     */
-    void endProperty();
-
-    /**
-     * @param group A group name. This method may be called more than once or may not be
-     * called at all, depending on how many gruoups are appended to the property.
-     */
-    void propertyGroup(String group);
-
-    /**
-     * @param name A property name like "N", "FN", "ADR", etc.
-     */
-    void propertyName(String name);
-
-    /**
-     * @param type A parameter name like "ENCODING", "CHARSET", etc.
-     */
-    void propertyParamType(String type);
-
-    /**
-     * @param value A parameter value. This method may be called without
-     * {@link #propertyParamType(String)} being called (when the vCard is vCard 2.1).
-     */
-    void propertyParamValue(String value);
-
-    /**
-     * @param values List of property values. The size of values would be 1 unless
-     * coressponding property name is "N", "ADR", or "ORG".
-     */
-    void propertyValues(List<String> values);
-}
diff --git a/vcard/java/com/android/vcard/VCardInterpreterCollection.java b/vcard/java/com/android/vcard/VCardInterpreterCollection.java
deleted file mode 100644
index 4a40d93..0000000
--- a/vcard/java/com/android/vcard/VCardInterpreterCollection.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * The {@link VCardInterpreter} implementation which aggregates more than one
- * {@link VCardInterpreter} objects and make a user object treat them as one
- * {@link VCardInterpreter} object.
- */
-public final class VCardInterpreterCollection implements VCardInterpreter {
-    private final Collection<VCardInterpreter> mInterpreterCollection;
-    
-    public VCardInterpreterCollection(Collection<VCardInterpreter> interpreterCollection) {
-        mInterpreterCollection = interpreterCollection;
-    }
-
-    public Collection<VCardInterpreter> getCollection() {
-        return mInterpreterCollection;
-    }
-
-    public void start() {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.start();
-        }
-    }
-
-    public void end() {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.end();
-        }
-    }
-
-    public void startEntry() {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.startEntry();
-        }
-    }
-
-    public void endEntry() {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.endEntry();
-        }
-    }
-
-    public void startProperty() {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.startProperty();
-        }
-    }
-
-    public void endProperty() {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.endProperty();
-        }
-    }
-
-    public void propertyGroup(String group) {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.propertyGroup(group);
-        }
-    }
-
-    public void propertyName(String name) {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.propertyName(name);
-        }
-    }
-
-    public void propertyParamType(String type) {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.propertyParamType(type);
-        }
-    }
-
-    public void propertyParamValue(String value) {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.propertyParamValue(value);
-        }
-    }
-
-    public void propertyValues(List<String> values) {
-        for (VCardInterpreter builder : mInterpreterCollection) {
-            builder.propertyValues(values);
-        }
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardParser.java b/vcard/java/com/android/vcard/VCardParser.java
deleted file mode 100644
index b7b8291..0000000
--- a/vcard/java/com/android/vcard/VCardParser.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public interface VCardParser {
-    /**
-     * <p>
-     * Parses the given stream and send the vCard data into VCardBuilderBase object.
-     * </p>.
-     * <p>
-     * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
-     * local encoding to it. For example, Japanese phone career uses Shift_JIS, which is
-     * formally allowed in vCard 2.1, but not allowed in vCard 3.0. In vCard 2.1,
-     * In some exreme case, it is allowed for vCard to have different charsets in one vCard.
-     * </p>
-     * <p>
-     * We recommend you use {@link VCardSourceDetector} and detect which kind of source the
-     * vCard comes from and explicitly specify a charset using the result.
-     * </p>
-     *
-     * @param is The source to parse.
-     * @param interepreter A {@link VCardInterpreter} object which used to construct data.
-     * @throws IOException, VCardException
-     */
-    public void parse(InputStream is, VCardInterpreter interepreter)
-            throws IOException, VCardException;
-
-    /**
-     * <p>
-     * Cancel parsing vCard. Useful when you want to stop the parse in the other threads.
-     * </p>
-     * <p>
-     * Actual cancel is done after parsing the current vcard.
-     * </p>
-     */
-    public abstract void cancel();
-}
diff --git a/vcard/java/com/android/vcard/VCardParserImpl_V21.java b/vcard/java/com/android/vcard/VCardParserImpl_V21.java
deleted file mode 100644
index b8343ae..0000000
--- a/vcard/java/com/android/vcard/VCardParserImpl_V21.java
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.util.Log;
-
-import com.android.vcard.exception.VCardAgentNotSupportedException;
-import com.android.vcard.exception.VCardException;
-import com.android.vcard.exception.VCardInvalidCommentLineException;
-import com.android.vcard.exception.VCardInvalidLineException;
-import com.android.vcard.exception.VCardNestedException;
-import com.android.vcard.exception.VCardVersionException;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * <p>
- * Basic implementation achieving vCard parsing. Based on vCard 2.1,
- * </p>
- * @hide
- */
-/* package */ class VCardParserImpl_V21 {
-    private static final String LOG_TAG = "VCardParserImpl_V21";
-
-    private static final class CustomBufferedReader extends BufferedReader {
-        private long mTime;
-
-        public CustomBufferedReader(Reader in) {
-            super(in);
-        }
-
-        @Override
-        public String readLine() throws IOException {
-            long start = System.currentTimeMillis();
-            String ret = super.readLine();
-            long end = System.currentTimeMillis();
-            mTime += end - start;
-            return ret;
-        }
-
-        public long getTotalmillisecond() {
-            return mTime;
-        }
-    }
-
-    private static final String DEFAULT_ENCODING = "8BIT";
-
-    protected boolean mCanceled;
-    protected VCardInterpreter mInterpreter;
-
-    protected final String mIntermediateCharset;
-
-    /**
-     * <p>
-     * The encoding type for deconding byte streams. This member variable is
-     * reset to a default encoding every time when a new item comes.
-     * </p>
-     * <p>
-     * "Encoding" in vCard is different from "Charset". It is mainly used for
-     * addresses, notes, images. "7BIT", "8BIT", "BASE64", and
-     * "QUOTED-PRINTABLE" are known examples.
-     * </p>
-     */
-    protected String mCurrentEncoding;
-
-    /**
-     * <p>
-     * The reader object to be used internally.
-     * </p>
-     * <p>
-     * Developers should not directly read a line from this object. Use
-     * getLine() unless there some reason.
-     * </p>
-     */
-    protected BufferedReader mReader;
-
-    /**
-     * <p>
-     * Set for storing unkonwn TYPE attributes, which is not acceptable in vCard
-     * specification, but happens to be seen in real world vCard.
-     * </p>
-     */
-    protected final Set<String> mUnknownTypeSet = new HashSet<String>();
-
-    /**
-     * <p>
-     * Set for storing unkonwn VALUE attributes, which is not acceptable in
-     * vCard specification, but happens to be seen in real world vCard.
-     * </p>
-     */
-    protected final Set<String> mUnknownValueSet = new HashSet<String>();
-
-
-    // In some cases, vCard is nested. Currently, we only consider the most
-    // interior vCard data.
-    // See v21_foma_1.vcf in test directory for more information.
-    // TODO: Don't ignore by using count, but read all of information outside vCard.
-    private int mNestCount;
-
-    // Used only for parsing END:VCARD.
-    private String mPreviousLine;
-
-    // For measuring performance.
-    private long mTimeTotal;
-    private long mTimeReadStartRecord;
-    private long mTimeReadEndRecord;
-    private long mTimeStartProperty;
-    private long mTimeEndProperty;
-    private long mTimeParseItems;
-    private long mTimeParseLineAndHandleGroup;
-    private long mTimeParsePropertyValues;
-    private long mTimeParseAdrOrgN;
-    private long mTimeHandleMiscPropertyValue;
-    private long mTimeHandleQuotedPrintable;
-    private long mTimeHandleBase64;
-
-    public VCardParserImpl_V21() {
-        this(VCardConfig.VCARD_TYPE_DEFAULT);
-    }
-
-    public VCardParserImpl_V21(int vcardType) {
-        if ((vcardType & VCardConfig.FLAG_TORELATE_NEST) != 0) {
-            mNestCount = 1;
-        }
-
-        mIntermediateCharset =  VCardConfig.DEFAULT_INTERMEDIATE_CHARSET;
-    }
-
-    /**
-     * <p>
-     * Parses the file at the given position.
-     * </p>
-     */
-    // <pre class="prettyprint">vcard_file = [wsls] vcard [wsls]</pre>
-    protected void parseVCardFile() throws IOException, VCardException {
-        boolean readingFirstFile = true;
-        while (true) {
-            if (mCanceled) {
-                break;
-            }
-            if (!parseOneVCard(readingFirstFile)) {
-                break;
-            }
-            readingFirstFile = false;
-        }
-
-        if (mNestCount > 0) {
-            boolean useCache = true;
-            for (int i = 0; i < mNestCount; i++) {
-                readEndVCard(useCache, true);
-                useCache = false;
-            }
-        }
-    }
-
-    /**
-     * @return true when a given property name is a valid property name.
-     */
-    protected boolean isValidPropertyName(final String propertyName) {
-        if (!(getKnownPropertyNameSet().contains(propertyName.toUpperCase()) ||
-                propertyName.startsWith("X-"))
-                && !mUnknownTypeSet.contains(propertyName)) {
-            mUnknownTypeSet.add(propertyName);
-            Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
-        }
-        return true;
-    }
-
-    /**
-     * @return String. It may be null, or its length may be 0
-     * @throws IOException
-     */
-    protected String getLine() throws IOException {
-        return mReader.readLine();
-    }
-
-    /**
-     * @return String with it's length > 0
-     * @throws IOException
-     * @throws VCardException when the stream reached end of line
-     */
-    protected String getNonEmptyLine() throws IOException, VCardException {
-        String line;
-        while (true) {
-            line = getLine();
-            if (line == null) {
-                throw new VCardException("Reached end of buffer.");
-            } else if (line.trim().length() > 0) {
-                return line;
-            }
-        }
-    }
-
-    /*
-     * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
-     *         items *CRLF
-     *         "END" [ws] ":" [ws] "VCARD"
-     */
-    private boolean parseOneVCard(boolean firstRead) throws IOException, VCardException {
-        boolean allowGarbage = false;
-        if (firstRead) {
-            if (mNestCount > 0) {
-                for (int i = 0; i < mNestCount; i++) {
-                    if (!readBeginVCard(allowGarbage)) {
-                        return false;
-                    }
-                    allowGarbage = true;
-                }
-            }
-        }
-
-        if (!readBeginVCard(allowGarbage)) {
-            return false;
-        }
-        long start;
-        if (mInterpreter != null) {
-            start = System.currentTimeMillis();
-            mInterpreter.startEntry();
-            mTimeReadStartRecord += System.currentTimeMillis() - start;
-        }
-        start = System.currentTimeMillis();
-        parseItems();
-        mTimeParseItems += System.currentTimeMillis() - start;
-        readEndVCard(true, false);
-        if (mInterpreter != null) {
-            start = System.currentTimeMillis();
-            mInterpreter.endEntry();
-            mTimeReadEndRecord += System.currentTimeMillis() - start;
-        }
-        return true;
-    }
-
-    /**
-     * @return True when successful. False when reaching the end of line
-     * @throws IOException
-     * @throws VCardException
-     */
-    protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
-        String line;
-        do {
-            while (true) {
-                line = getLine();
-                if (line == null) {
-                    return false;
-                } else if (line.trim().length() > 0) {
-                    break;
-                }
-            }
-            String[] strArray = line.split(":", 2);
-            int length = strArray.length;
-
-            // Though vCard 2.1/3.0 specification does not allow lower cases,
-            // vCard file emitted by some external vCard expoter have such
-            // invalid Strings.
-            // So we allow it.
-            // e.g. BEGIN:vCard
-            if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN")
-                    && strArray[1].trim().equalsIgnoreCase("VCARD")) {
-                return true;
-            } else if (!allowGarbage) {
-                if (mNestCount > 0) {
-                    mPreviousLine = line;
-                    return false;
-                } else {
-                    throw new VCardException("Expected String \"BEGIN:VCARD\" did not come "
-                            + "(Instead, \"" + line + "\" came)");
-                }
-            }
-        } while (allowGarbage);
-
-        throw new VCardException("Reached where must not be reached.");
-    }
-
-    /**
-     * <p>
-     * The arguments useCache and allowGarbase are usually true and false
-     * accordingly when this function is called outside this function itself.
-     * </p>
-     * 
-     * @param useCache When true, line is obtained from mPreviousline.
-     *            Otherwise, getLine() is used.
-     * @param allowGarbage When true, ignore non "END:VCARD" line.
-     * @throws IOException
-     * @throws VCardException
-     */
-    protected void readEndVCard(boolean useCache, boolean allowGarbage) throws IOException,
-            VCardException {
-        String line;
-        do {
-            if (useCache) {
-                // Though vCard specification does not allow lower cases,
-                // some data may have them, so we allow it.
-                line = mPreviousLine;
-            } else {
-                while (true) {
-                    line = getLine();
-                    if (line == null) {
-                        throw new VCardException("Expected END:VCARD was not found.");
-                    } else if (line.trim().length() > 0) {
-                        break;
-                    }
-                }
-            }
-
-            String[] strArray = line.split(":", 2);
-            if (strArray.length == 2 && strArray[0].trim().equalsIgnoreCase("END")
-                    && strArray[1].trim().equalsIgnoreCase("VCARD")) {
-                return;
-            } else if (!allowGarbage) {
-                throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
-            }
-            useCache = false;
-        } while (allowGarbage);
-    }
-
-    /*
-     * items = *CRLF item / item
-     */
-    protected void parseItems() throws IOException, VCardException {
-        boolean ended = false;
-
-        if (mInterpreter != null) {
-            long start = System.currentTimeMillis();
-            mInterpreter.startProperty();
-            mTimeStartProperty += System.currentTimeMillis() - start;
-        }
-        ended = parseItem();
-        if (mInterpreter != null && !ended) {
-            long start = System.currentTimeMillis();
-            mInterpreter.endProperty();
-            mTimeEndProperty += System.currentTimeMillis() - start;
-        }
-
-        while (!ended) {
-            // follow VCARD ,it wont reach endProperty
-            if (mInterpreter != null) {
-                long start = System.currentTimeMillis();
-                mInterpreter.startProperty();
-                mTimeStartProperty += System.currentTimeMillis() - start;
-            }
-            try {
-                ended = parseItem();
-            } catch (VCardInvalidCommentLineException e) {
-                Log.e(LOG_TAG, "Invalid line which looks like some comment was found. Ignored.");
-                ended = false;
-            }
-            if (mInterpreter != null && !ended) {
-                long start = System.currentTimeMillis();
-                mInterpreter.endProperty();
-                mTimeEndProperty += System.currentTimeMillis() - start;
-            }
-        }
-    }
-
-    /*
-     * item = [groups "."] name [params] ":" value CRLF / [groups "."] "ADR"
-     * [params] ":" addressparts CRLF / [groups "."] "ORG" [params] ":" orgparts
-     * CRLF / [groups "."] "N" [params] ":" nameparts CRLF / [groups "."]
-     * "AGENT" [params] ":" vcard CRLF
-     */
-    protected boolean parseItem() throws IOException, VCardException {
-        mCurrentEncoding = DEFAULT_ENCODING;
-
-        final String line = getNonEmptyLine();
-        long start = System.currentTimeMillis();
-
-        String[] propertyNameAndValue = separateLineAndHandleGroup(line);
-        if (propertyNameAndValue == null) {
-            return true;
-        }
-        if (propertyNameAndValue.length != 2) {
-            throw new VCardInvalidLineException("Invalid line \"" + line + "\"");
-        }
-        String propertyName = propertyNameAndValue[0].toUpperCase();
-        String propertyValue = propertyNameAndValue[1];
-
-        mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start;
-
-        if (propertyName.equals("ADR") || propertyName.equals("ORG") || propertyName.equals("N")) {
-            start = System.currentTimeMillis();
-            handleMultiplePropertyValue(propertyName, propertyValue);
-            mTimeParseAdrOrgN += System.currentTimeMillis() - start;
-            return false;
-        } else if (propertyName.equals("AGENT")) {
-            handleAgent(propertyValue);
-            return false;
-        } else if (isValidPropertyName(propertyName)) {
-            if (propertyName.equals("BEGIN")) {
-                if (propertyValue.equals("VCARD")) {
-                    throw new VCardNestedException("This vCard has nested vCard data in it.");
-                } else {
-                    throw new VCardException("Unknown BEGIN type: " + propertyValue);
-                }
-            } else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersionString())) {
-                throw new VCardVersionException("Incompatible version: " + propertyValue + " != "
-                        + getVersionString());
-            }
-            start = System.currentTimeMillis();
-            handlePropertyValue(propertyName, propertyValue);
-            mTimeParsePropertyValues += System.currentTimeMillis() - start;
-            return false;
-        }
-
-        throw new VCardException("Unknown property name: \"" + propertyName + "\"");
-    }
-
-    // For performance reason, the states for group and property name are merged into one.
-    static private final int STATE_GROUP_OR_PROPERTY_NAME = 0;
-    static private final int STATE_PARAMS = 1;
-    // vCard 3.0 specification allows double-quoted parameters, while vCard 2.1 does not.
-    static private final int STATE_PARAMS_IN_DQUOTE = 2;
-
-    protected String[] separateLineAndHandleGroup(String line) throws VCardException {
-        final String[] propertyNameAndValue = new String[2];
-        final int length = line.length();
-        if (length > 0 && line.charAt(0) == '#') {
-            throw new VCardInvalidCommentLineException();
-        }
-
-        int state = STATE_GROUP_OR_PROPERTY_NAME;
-        int nameIndex = 0;
-
-        // This loop is developed so that we don't have to take care of bottle neck here.
-        // Refactor carefully when you need to do so.
-        for (int i = 0; i < length; i++) {
-            final char ch = line.charAt(i);
-            switch (state) {
-                case STATE_GROUP_OR_PROPERTY_NAME: {
-                    if (ch == ':') {  // End of a property name.
-                        final String propertyName = line.substring(nameIndex, i);
-                        if (propertyName.equalsIgnoreCase("END")) {
-                            mPreviousLine = line;
-                            return null;
-                        }
-                        if (mInterpreter != null) {
-                            mInterpreter.propertyName(propertyName);
-                        }
-                        propertyNameAndValue[0] = propertyName;
-                        if (i < length - 1) {
-                            propertyNameAndValue[1] = line.substring(i + 1);
-                        } else {
-                            propertyNameAndValue[1] = "";
-                        }
-                        return propertyNameAndValue;
-                    } else if (ch == '.') {  // Each group is followed by the dot.
-                        final String groupName = line.substring(nameIndex, i);
-                        if (groupName.length() == 0) {
-                            Log.w(LOG_TAG, "Empty group found. Ignoring.");
-                        } else if (mInterpreter != null) {
-                            mInterpreter.propertyGroup(groupName);
-                        }
-                        nameIndex = i + 1;  // Next should be another group or a property name.
-                    } else if (ch == ';') {  // End of property name and beginneng of parameters.  
-                        final String propertyName = line.substring(nameIndex, i);
-                        if (propertyName.equalsIgnoreCase("END")) {
-                            mPreviousLine = line;
-                            return null;
-                        }
-                        if (mInterpreter != null) {
-                            mInterpreter.propertyName(propertyName);
-                        }
-                        propertyNameAndValue[0] = propertyName;
-                        nameIndex = i + 1;
-                        state = STATE_PARAMS;  // Start parameter parsing.
-                    }
-                    break;
-                }
-                case STATE_PARAMS: {
-                    if (ch == '"') {
-                        if (VCardConstants.VERSION_V21.equalsIgnoreCase(getVersionString())) {
-                            Log.w(LOG_TAG, "Double-quoted params found in vCard 2.1. " +
-                                    "Silently allow it");
-                        }
-                        state = STATE_PARAMS_IN_DQUOTE;
-                    } else if (ch == ';') {  // Starts another param.
-                        handleParams(line.substring(nameIndex, i));
-                        nameIndex = i + 1;
-                    } else if (ch == ':') {  // End of param and beginenning of values.
-                        handleParams(line.substring(nameIndex, i));
-                        if (i < length - 1) {
-                            propertyNameAndValue[1] = line.substring(i + 1);
-                        } else {
-                            propertyNameAndValue[1] = "";
-                        }
-                        return propertyNameAndValue;
-                    }
-                    break;
-                }
-                case STATE_PARAMS_IN_DQUOTE: {
-                    if (ch == '"') {
-                        if (VCardConstants.VERSION_V21.equalsIgnoreCase(getVersionString())) {
-                            Log.w(LOG_TAG, "Double-quoted params found in vCard 2.1. " +
-                                    "Silently allow it");
-                        }
-                        state = STATE_PARAMS;
-                    }
-                    break;
-                }
-            }
-        }
-
-        throw new VCardInvalidLineException("Invalid line: \"" + line + "\"");
-    }
-
-    /*
-     * params = ";" [ws] paramlist paramlist = paramlist [ws] ";" [ws] param /
-     * param param = "TYPE" [ws] "=" [ws] ptypeval / "VALUE" [ws] "=" [ws]
-     * pvalueval / "ENCODING" [ws] "=" [ws] pencodingval / "CHARSET" [ws] "="
-     * [ws] charsetval / "LANGUAGE" [ws] "=" [ws] langval / "X-" word [ws] "="
-     * [ws] word / knowntype
-     */
-    protected void handleParams(String params) throws VCardException {
-        final String[] strArray = params.split("=", 2);
-        if (strArray.length == 2) {
-            final String paramName = strArray[0].trim().toUpperCase();
-            String paramValue = strArray[1].trim();
-            if (paramName.equals("TYPE")) {
-                handleType(paramValue);
-            } else if (paramName.equals("VALUE")) {
-                handleValue(paramValue);
-            } else if (paramName.equals("ENCODING")) {
-                handleEncoding(paramValue);
-            } else if (paramName.equals("CHARSET")) {
-                handleCharset(paramValue);
-            } else if (paramName.equals("LANGUAGE")) {
-                handleLanguage(paramValue);
-            } else if (paramName.startsWith("X-")) {
-                handleAnyParam(paramName, paramValue);
-            } else {
-                throw new VCardException("Unknown type \"" + paramName + "\"");
-            }
-        } else {
-            handleParamWithoutName(strArray[0]);
-        }
-    }
-
-    /**
-     * vCard 3.0 parser implementation may throw VCardException.
-     */
-    @SuppressWarnings("unused")
-    protected void handleParamWithoutName(final String paramValue) throws VCardException {
-        handleType(paramValue);
-    }
-
-    /*
-     * ptypeval = knowntype / "X-" word
-     */
-    protected void handleType(final String ptypeval) {
-        if (!(getKnownTypeSet().contains(ptypeval.toUpperCase())
-                || ptypeval.startsWith("X-"))
-                && !mUnknownTypeSet.contains(ptypeval)) {
-            mUnknownTypeSet.add(ptypeval);
-            Log.w(LOG_TAG, String.format("TYPE unsupported by %s: ", getVersion(), ptypeval));
-        }
-        if (mInterpreter != null) {
-            mInterpreter.propertyParamType("TYPE");
-            mInterpreter.propertyParamValue(ptypeval);
-        }
-    }
-
-    /*
-     * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
-     */
-    protected void handleValue(final String pvalueval) {
-        if (!(getKnownValueSet().contains(pvalueval.toUpperCase())
-                || pvalueval.startsWith("X-")
-                || mUnknownValueSet.contains(pvalueval))) {
-            mUnknownValueSet.add(pvalueval);
-            Log.w(LOG_TAG, String.format(
-                    "The value unsupported by TYPE of %s: ", getVersion(), pvalueval));
-        }
-        if (mInterpreter != null) {
-            mInterpreter.propertyParamType("VALUE");
-            mInterpreter.propertyParamValue(pvalueval);
-        }
-    }
-
-    /*
-     * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
-     */
-    protected void handleEncoding(String pencodingval) throws VCardException {
-        if (getAvailableEncodingSet().contains(pencodingval) ||
-                pencodingval.startsWith("X-")) {
-            if (mInterpreter != null) {
-                mInterpreter.propertyParamType("ENCODING");
-                mInterpreter.propertyParamValue(pencodingval);
-            }
-            mCurrentEncoding = pencodingval;
-        } else {
-            throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
-        }
-    }
-
-    /**
-     * <p>
-     * vCard 2.1 specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
-     * but recent vCard files often contain other charset like UTF-8, SHIFT_JIS, etc.
-     * We allow any charset.
-     * </p>
-     */
-    protected void handleCharset(String charsetval) {
-        if (mInterpreter != null) {
-            mInterpreter.propertyParamType("CHARSET");
-            mInterpreter.propertyParamValue(charsetval);
-        }
-    }
-
-    /**
-     * See also Section 7.1 of RFC 1521
-     */
-    protected void handleLanguage(String langval) throws VCardException {
-        String[] strArray = langval.split("-");
-        if (strArray.length != 2) {
-            throw new VCardException("Invalid Language: \"" + langval + "\"");
-        }
-        String tmp = strArray[0];
-        int length = tmp.length();
-        for (int i = 0; i < length; i++) {
-            if (!isAsciiLetter(tmp.charAt(i))) {
-                throw new VCardException("Invalid Language: \"" + langval + "\"");
-            }
-        }
-        tmp = strArray[1];
-        length = tmp.length();
-        for (int i = 0; i < length; i++) {
-            if (!isAsciiLetter(tmp.charAt(i))) {
-                throw new VCardException("Invalid Language: \"" + langval + "\"");
-            }
-        }
-        if (mInterpreter != null) {
-            mInterpreter.propertyParamType("LANGUAGE");
-            mInterpreter.propertyParamValue(langval);
-        }
-    }
-
-    private boolean isAsciiLetter(char ch) {
-        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Mainly for "X-" type. This accepts any kind of type without check.
-     */
-    protected void handleAnyParam(String paramName, String paramValue) {
-        if (mInterpreter != null) {
-            mInterpreter.propertyParamType(paramName);
-            mInterpreter.propertyParamValue(paramValue);
-        }
-    }
-
-    protected void handlePropertyValue(String propertyName, String propertyValue)
-            throws IOException, VCardException {
-        final String upperEncoding = mCurrentEncoding.toUpperCase();
-        if (upperEncoding.equals(VCardConstants.PARAM_ENCODING_QP)) {
-            final long start = System.currentTimeMillis();
-            final String result = getQuotedPrintable(propertyValue);
-            if (mInterpreter != null) {
-                ArrayList<String> v = new ArrayList<String>();
-                v.add(result);
-                mInterpreter.propertyValues(v);
-            }
-            mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
-        } else if (upperEncoding.equals(VCardConstants.PARAM_ENCODING_BASE64)
-                || upperEncoding.equals(VCardConstants.PARAM_ENCODING_B)) {
-            final long start = System.currentTimeMillis();
-            // It is very rare, but some BASE64 data may be so big that
-            // OutOfMemoryError occurs. To ignore such cases, use try-catch.
-            try {
-                final String result = getBase64(propertyValue);
-                if (mInterpreter != null) {
-                    ArrayList<String> arrayList = new ArrayList<String>();
-                    arrayList.add(result);
-                    mInterpreter.propertyValues(arrayList);
-                }
-            } catch (OutOfMemoryError error) {
-                Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
-                if (mInterpreter != null) {
-                    mInterpreter.propertyValues(null);
-                }
-            }
-            mTimeHandleBase64 += System.currentTimeMillis() - start;
-        } else {
-            if (!(upperEncoding.equals("7BIT") || upperEncoding.equals("8BIT") ||
-                    upperEncoding.startsWith("X-"))) {
-                Log.w(LOG_TAG,
-                        String.format("The encoding \"%s\" is unsupported by vCard %s",
-                                mCurrentEncoding, getVersionString()));
-            }
-
-            final long start = System.currentTimeMillis();
-            if (mInterpreter != null) {
-                ArrayList<String> v = new ArrayList<String>();
-                v.add(maybeUnescapeText(propertyValue));
-                mInterpreter.propertyValues(v);
-            }
-            mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start;
-        }
-    }
-
-    /**
-     * <p>
-     * Parses and returns Quoted-Printable.
-     * </p>
-     *
-     * @param firstString The string following a parameter name and attributes.
-     *            Example: "string" in
-     *            "ADR:ENCODING=QUOTED-PRINTABLE:string\n\r".
-     * @return whole Quoted-Printable string, including a given argument and
-     *         following lines. Excludes the last empty line following to Quoted
-     *         Printable lines.
-     * @throws IOException
-     * @throws VCardException
-     */
-    private String getQuotedPrintable(String firstString) throws IOException, VCardException {
-        // Specifically, there may be some padding between = and CRLF.
-        // See the following:
-        //
-        // qp-line := *(qp-segment transport-padding CRLF)
-        // qp-part transport-padding
-        // qp-segment := qp-section *(SPACE / TAB) "="
-        // ; Maximum length of 76 characters
-        //
-        // e.g. (from RFC 2045)
-        // Now's the time =
-        // for all folk to come=
-        // to the aid of their country.
-        if (firstString.trim().endsWith("=")) {
-            // remove "transport-padding"
-            int pos = firstString.length() - 1;
-            while (firstString.charAt(pos) != '=') {
-            }
-            StringBuilder builder = new StringBuilder();
-            builder.append(firstString.substring(0, pos + 1));
-            builder.append("\r\n");
-            String line;
-            while (true) {
-                line = getLine();
-                if (line == null) {
-                    throw new VCardException("File ended during parsing a Quoted-Printable String");
-                }
-                if (line.trim().endsWith("=")) {
-                    // remove "transport-padding"
-                    pos = line.length() - 1;
-                    while (line.charAt(pos) != '=') {
-                    }
-                    builder.append(line.substring(0, pos + 1));
-                    builder.append("\r\n");
-                } else {
-                    builder.append(line);
-                    break;
-                }
-            }
-            return builder.toString();
-        } else {
-            return firstString;
-        }
-    }
-
-    protected String getBase64(String firstString) throws IOException, VCardException {
-        StringBuilder builder = new StringBuilder();
-        builder.append(firstString);
-
-        while (true) {
-            String line = getLine();
-            if (line == null) {
-                throw new VCardException("File ended during parsing BASE64 binary");
-            }
-            if (line.length() == 0) {
-                break;
-            }
-            builder.append(line);
-        }
-
-        return builder.toString();
-    }
-
-    /**
-     * <p>
-     * Mainly for "ADR", "ORG", and "N"
-     * </p>
-     */
-    /*
-     * addressparts = 0*6(strnosemi ";") strnosemi ; PO Box, Extended Addr,
-     * Street, Locality, Region, Postal Code, Country Name orgparts =
-     * *(strnosemi ";") strnosemi ; First is Organization Name, remainder are
-     * Organization Units. nameparts = 0*4(strnosemi ";") strnosemi ; Family,
-     * Given, Middle, Prefix, Suffix. ; Example:Public;John;Q.;Reverend Dr.;III,
-     * Esq. strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi ; To include a
-     * semicolon in this string, it must be escaped ; with a "\" character. We
-     * do not care the number of "strnosemi" here. We are not sure whether we
-     * should add "\" CRLF to each value. We exclude them for now.
-     */
-    protected void handleMultiplePropertyValue(String propertyName, String propertyValue)
-            throws IOException, VCardException {
-        // vCard 2.1 does not allow QUOTED-PRINTABLE here, but some
-        // softwares/devices
-        // emit such data.
-        if (mCurrentEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
-            propertyValue = getQuotedPrintable(propertyValue);
-        }
-
-        if (mInterpreter != null) {
-            mInterpreter.propertyValues(VCardUtils.constructListFromValue(propertyValue,
-                    (getVersion() == VCardConfig.FLAG_V30)));
-        }
-    }
-
-    /*
-     * vCard 2.1 specifies AGENT allows one vcard entry. Currently we emit an
-     * error toward the AGENT property.
-     * // TODO: Support AGENT property.
-     * item =
-     * ... / [groups "."] "AGENT" [params] ":" vcard CRLF vcard = "BEGIN" [ws]
-     * ":" [ws] "VCARD" [ws] 1*CRLF items *CRLF "END" [ws] ":" [ws] "VCARD"
-     */
-    protected void handleAgent(final String propertyValue) throws VCardException {
-        if (!propertyValue.toUpperCase().contains("BEGIN:VCARD")) {
-            // Apparently invalid line seen in Windows Mobile 6.5. Ignore them.
-            return;
-        } else {
-            throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");
-        }
-    }
-
-    /**
-     * For vCard 3.0.
-     */
-    protected String maybeUnescapeText(final String text) {
-        return text;
-    }
-
-    /**
-     * Returns unescaped String if the character should be unescaped. Return
-     * null otherwise. e.g. In vCard 2.1, "\;" should be unescaped into ";"
-     * while "\x" should not be.
-     */
-    protected String maybeUnescapeCharacter(final char ch) {
-        return unescapeCharacter(ch);
-    }
-
-    /* package */ static String unescapeCharacter(final char ch) {
-        // Original vCard 2.1 specification does not allow transformation
-        // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous
-        // implementation of
-        // this class allowed them, so keep it as is.
-        if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') {
-            return String.valueOf(ch);
-        } else {
-            return null;
-        }
-    }
-
-    private void showPerformanceInfo() {
-        Log.d(LOG_TAG, "Total parsing time:  " + mTimeTotal + " ms");
-        if (mReader instanceof CustomBufferedReader) {
-            Log.d(LOG_TAG, "Total readLine time: "
-                    + ((CustomBufferedReader) mReader).getTotalmillisecond() + " ms");
-        }
-        Log.d(LOG_TAG, "Time for handling the beggining of the record: " + mTimeReadStartRecord
-                + " ms");
-        Log.d(LOG_TAG, "Time for handling the end of the record: " + mTimeReadEndRecord + " ms");
-        Log.d(LOG_TAG, "Time for parsing line, and handling group: " + mTimeParseLineAndHandleGroup
-                + " ms");
-        Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms");
-        Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms");
-        Log.d(LOG_TAG, "Time for handling normal property values: " + mTimeHandleMiscPropertyValue
-                + " ms");
-        Log.d(LOG_TAG, "Time for handling Quoted-Printable: " + mTimeHandleQuotedPrintable + " ms");
-        Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms");
-    }
-
-    /**
-     * @return {@link VCardConfig#FLAG_V21}
-     */
-    protected int getVersion() {
-        return VCardConfig.FLAG_V21;
-    }
-
-    /**
-     * @return {@link VCardConfig#FLAG_V30}
-     */
-    protected String getVersionString() {
-        return VCardConstants.VERSION_V21;
-    }
-
-    protected Set<String> getKnownPropertyNameSet() {
-        return VCardParser_V21.sKnownPropertyNameSet;
-    }
-
-    protected Set<String> getKnownTypeSet() {
-        return VCardParser_V21.sKnownTypeSet;
-    }
-
-    protected Set<String> getKnownValueSet() {
-        return VCardParser_V21.sKnownValueSet;
-    }
-
-    protected Set<String> getAvailableEncodingSet() {
-        return VCardParser_V21.sAvailableEncoding;
-    }
-
-    protected String getDefaultEncoding() {
-        return DEFAULT_ENCODING;
-    }
-
-
-    public void parse(InputStream is, VCardInterpreter interpreter)
-            throws IOException, VCardException {
-        if (is == null) {
-            throw new NullPointerException("InputStream must not be null.");
-        }
-
-        final InputStreamReader tmpReader = new InputStreamReader(is, mIntermediateCharset);
-        if (VCardConfig.showPerformanceLog()) {
-            mReader = new CustomBufferedReader(tmpReader);
-        } else {
-            mReader = new BufferedReader(tmpReader);
-        }
-
-        mInterpreter = interpreter;
-
-        final long start = System.currentTimeMillis();
-        if (mInterpreter != null) {
-            mInterpreter.start();
-        }
-        parseVCardFile();
-        if (mInterpreter != null) {
-            mInterpreter.end();
-        }
-        mTimeTotal += System.currentTimeMillis() - start;
-
-        if (VCardConfig.showPerformanceLog()) {
-            showPerformanceInfo();
-        }
-    }
-
-    public final void cancel() {
-        mCanceled = true;
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardParserImpl_V30.java b/vcard/java/com/android/vcard/VCardParserImpl_V30.java
deleted file mode 100644
index def1495..0000000
--- a/vcard/java/com/android/vcard/VCardParserImpl_V30.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.util.Log;
-
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.util.Set;
-
-/**
- * <p>
- * Basic implementation achieving vCard 3.0 parsing.
- * </p>
- * <p>
- * This class inherits vCard 2.1 implementation since technically they are similar,
- * while specifically there's logical no relevance between them.
- * So that developers are not confused with the inheritance,
- * {@link VCardParser_V30} does not inherit {@link VCardParser_V21}, while
- * {@link VCardParserImpl_V30} inherits {@link VCardParserImpl_V21}.
- * </p>
- * @hide
- */
-/* package */ class VCardParserImpl_V30 extends VCardParserImpl_V21 {
-    private static final String LOG_TAG = "VCardParserImpl_V30";
-
-    private String mPreviousLine;
-    private boolean mEmittedAgentWarning = false;
-
-    public VCardParserImpl_V30() {
-        super();
-    }
-
-    public VCardParserImpl_V30(int vcardType) {
-        super(vcardType);
-    }
-
-    @Override
-    protected int getVersion() {
-        return VCardConfig.FLAG_V30;
-    }
-
-    @Override
-    protected String getVersionString() {
-        return VCardConstants.VERSION_V30;
-    }
-
-    @Override
-    protected String getLine() throws IOException {
-        if (mPreviousLine != null) {
-            String ret = mPreviousLine;
-            mPreviousLine = null;
-            return ret;
-        } else {
-            return mReader.readLine();
-        }
-    }
-
-    /**
-     * vCard 3.0 requires that the line with space at the beginning of the line
-     * must be combined with previous line.
-     */
-    @Override
-    protected String getNonEmptyLine() throws IOException, VCardException {
-        String line;
-        StringBuilder builder = null;
-        while (true) {
-            line = mReader.readLine();
-            if (line == null) {
-                if (builder != null) {
-                    return builder.toString();
-                } else if (mPreviousLine != null) {
-                    String ret = mPreviousLine;
-                    mPreviousLine = null;
-                    return ret;
-                }
-                throw new VCardException("Reached end of buffer.");
-            } else if (line.length() == 0) {
-                if (builder != null) {
-                    return builder.toString();
-                } else if (mPreviousLine != null) {
-                    String ret = mPreviousLine;
-                    mPreviousLine = null;
-                    return ret;
-                }
-            } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
-                if (builder != null) {
-                    // See Section 5.8.1 of RFC 2425 (MIME-DIR document).
-                    // Following is the excerpts from it.
-                    //
-                    // DESCRIPTION:This is a long description that exists on a long line.
-                    //
-                    // Can be represented as:
-                    //
-                    // DESCRIPTION:This is a long description
-                    //  that exists on a long line.
-                    //
-                    // It could also be represented as:
-                    //
-                    // DESCRIPTION:This is a long descrip
-                    //  tion that exists o
-                    //  n a long line.
-                    builder.append(line.substring(1));
-                } else if (mPreviousLine != null) {
-                    builder = new StringBuilder();
-                    builder.append(mPreviousLine);
-                    mPreviousLine = null;
-                    builder.append(line.substring(1));
-                } else {
-                    throw new VCardException("Space exists at the beginning of the line");
-                }
-            } else {
-                if (mPreviousLine == null) {
-                    mPreviousLine = line;
-                    if (builder != null) {
-                        return builder.toString();
-                    }
-                } else {
-                    String ret = mPreviousLine;
-                    mPreviousLine = line;
-                    return ret;
-                }
-            }
-        }
-    }
-
-    /*
-     * vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF
-     *         1 * (contentline)
-     *         ;A vCard object MUST include the VERSION, FN and N types.
-     *         [group "."] "END" ":" "VCARD" 1 * CRLF
-     */
-    @Override
-    protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
-        // TODO: vCard 3.0 supports group.
-        return super.readBeginVCard(allowGarbage);
-    }
-
-    @Override
-    protected void readEndVCard(boolean useCache, boolean allowGarbage)
-            throws IOException, VCardException {
-        // TODO: vCard 3.0 supports group.
-        super.readEndVCard(useCache, allowGarbage);
-    }
-
-    /**
-     * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
-     */
-    @Override
-    protected void handleParams(final String params) throws VCardException {
-        try {
-            super.handleParams(params);
-        } catch (VCardException e) {
-            // maybe IANA type
-            String[] strArray = params.split("=", 2);
-            if (strArray.length == 2) {
-                handleAnyParam(strArray[0], strArray[1]);
-            } else {
-                // Must not come here in the current implementation.
-                throw new VCardException(
-                        "Unknown params value: " + params);
-            }
-        }
-    }
-
-    @Override
-    protected void handleAnyParam(final String paramName, final String paramValue) {
-        super.handleAnyParam(paramName, paramValue);
-    }
-
-    @Override
-    protected void handleParamWithoutName(final String paramValue) throws VCardException {
-        super.handleParamWithoutName(paramValue);
-    }
-
-    /*
-     *  vCard 3.0 defines
-     *
-     *  param         = param-name "=" param-value *("," param-value)
-     *  param-name    = iana-token / x-name
-     *  param-value   = ptext / quoted-string
-     *  quoted-string = DQUOTE QSAFE-CHAR DQUOTE
-     */
-    @Override
-    protected void handleType(final String ptypevalues) {
-        String[] ptypeArray = ptypevalues.split(",");
-        mInterpreter.propertyParamType("TYPE");
-        for (String value : ptypeArray) {
-            int length = value.length();
-            if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
-                mInterpreter.propertyParamValue(value.substring(1, value.length() - 1));
-            } else {
-                mInterpreter.propertyParamValue(value);
-            }
-        }
-    }
-
-    @Override
-    protected void handleAgent(final String propertyValue) {
-        // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1.
-        //
-        // e.g.
-        // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
-        //  TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
-        //  ET:jfriday@host.com\nEND:VCARD\n
-        //
-        // TODO: fix this.
-        //
-        // issue:
-        //  vCard 3.0 also allows this as an example.
-        //
-        // AGENT;VALUE=uri:
-        //  CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
-        //
-        // This is not vCard. Should we support this?
-        //
-        // Just ignore the line for now, since we cannot know how to handle it...
-        if (!mEmittedAgentWarning) {
-            Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it");
-            mEmittedAgentWarning = true;
-        }
-    }
-
-    /**
-     * vCard 3.0 does not require two CRLF at the last of BASE64 data.
-     * It only requires that data should be MIME-encoded.
-     */
-    @Override
-    protected String getBase64(final String firstString)
-            throws IOException, VCardException {
-        final StringBuilder builder = new StringBuilder();
-        builder.append(firstString);
-
-        while (true) {
-            final String line = getLine();
-            if (line == null) {
-                throw new VCardException("File ended during parsing BASE64 binary");
-            }
-            if (line.length() == 0) {
-                break;
-            } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
-                mPreviousLine = line;
-                break;
-            }
-            builder.append(line);
-        }
-
-        return builder.toString();
-    }
-
-    /**
-     * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
-     *              ; \\ encodes \, \n or \N encodes newline
-     *              ; \; encodes ;, \, encodes ,
-     *
-     * Note: Apple escapes ':' into '\:' while does not escape '\'
-     */
-    @Override
-    protected String maybeUnescapeText(final String text) {
-        return unescapeText(text);
-    }
-
-    public static String unescapeText(final String text) {
-        StringBuilder builder = new StringBuilder();
-        final int length = text.length();
-        for (int i = 0; i < length; i++) {
-            char ch = text.charAt(i);
-            if (ch == '\\' && i < length - 1) {
-                final char next_ch = text.charAt(++i);
-                if (next_ch == 'n' || next_ch == 'N') {
-                    builder.append("\n");
-                } else {
-                    builder.append(next_ch);
-                }
-            } else {
-                builder.append(ch);
-            }
-        }
-        return builder.toString();
-    }
-
-    @Override
-    protected String maybeUnescapeCharacter(final char ch) {
-        return unescapeCharacter(ch);
-    }
-
-    public static String unescapeCharacter(final char ch) {
-        if (ch == 'n' || ch == 'N') {
-            return "\n";
-        } else {
-            return String.valueOf(ch);
-        }
-    }
-
-    @Override
-    protected Set<String> getKnownPropertyNameSet() {
-        return VCardParser_V30.sKnownPropertyNameSet;
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardParser_V21.java b/vcard/java/com/android/vcard/VCardParser_V21.java
deleted file mode 100644
index 7aa7a82..0000000
--- a/vcard/java/com/android/vcard/VCardParser_V21.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * </p>
- * vCard parser for vCard 2.1. See the specification for more detail about the spec itself.
- * </p>
- * <p>
- * The spec is written in 1996, and currently various types of "vCard 2.1" exist.
- * To handle real the world vCard formats appropriately and effectively, this class does not
- * obey with strict vCard 2.1.
- * In stead, not only vCard spec but also real world vCard is considered.
- * </p>
- * e.g. A lot of devices and softwares let vCard importer/exporter to use
- * the PNG format to determine the type of image, while it is not allowed in
- * the original specification. As of 2010, we can see even the FLV format
- * (possible in Japanese mobile phones).
- * </p>
- */
-public final class VCardParser_V21 implements VCardParser {
-    /**
-     * A unmodifiable Set storing the property names available in the vCard 2.1 specification.
-     */
-    /* package */ static final Set<String> sKnownPropertyNameSet =
-            Collections.unmodifiableSet(new HashSet<String>(
-                    Arrays.asList("BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
-                            "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
-                            "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER")));
-
-    /**
-     * A unmodifiable Set storing the types known in vCard 2.1.
-     */
-    /* package */ static final Set<String> sKnownTypeSet =
-            Collections.unmodifiableSet(new HashSet<String>(
-                    Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
-                            "PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
-                            "MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
-                            "ATTMAIL", "CIS", "EWORLD", "INTERNET", "IBMMAIL",
-                            "MCIMAIL", "POWERSHARE", "PRODIGY", "TLX", "X400", "GIF",
-                            "CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
-                            "PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
-                            "WAVE", "AIFF", "PCM", "X509", "PGP")));
-
-    /**
-     * A unmodifiable Set storing the values for the type "VALUE", available in the vCard 2.1.
-     */
-    /* package */ static final Set<String> sKnownValueSet =
-            Collections.unmodifiableSet(new HashSet<String>(
-                    Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID")));
-
-    /**
-     * <p>
-     * A unmodifiable Set storing the values for the type "ENCODING", available in the vCard 2.1.
-     * </p>
-     * <p>
-     * Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
-     * We allow it for safety.
-     * </p>
-     */
-    /* package */ static final Set<String> sAvailableEncoding =
-        Collections.unmodifiableSet(new HashSet<String>(
-                Arrays.asList(VCardConstants.PARAM_ENCODING_7BIT,
-                        VCardConstants.PARAM_ENCODING_8BIT,
-                        VCardConstants.PARAM_ENCODING_QP,
-                        VCardConstants.PARAM_ENCODING_BASE64,
-                        VCardConstants.PARAM_ENCODING_B)));
-
-    private final VCardParserImpl_V21 mVCardParserImpl;
-
-    public VCardParser_V21() {
-        mVCardParserImpl = new VCardParserImpl_V21();
-    }
-
-    public VCardParser_V21(int vcardType) {
-        mVCardParserImpl = new VCardParserImpl_V21(vcardType);
-    }
-
-    public void parse(InputStream is, VCardInterpreter interepreter)
-            throws IOException, VCardException {
-        mVCardParserImpl.parse(is, interepreter);
-    }
-
-    public void cancel() {
-        mVCardParserImpl.cancel();
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardParser_V30.java b/vcard/java/com/android/vcard/VCardParser_V30.java
deleted file mode 100644
index 475534c..0000000
--- a/vcard/java/com/android/vcard/VCardParser_V30.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * <p>
- * vCard parser for vCard 3.0. See RFC 2426 for more detail.
- * </p>
- * <p>
- * This parser allows vCard format which is not allowed in the RFC, since
- * we have seen several vCard 3.0 files which don't comply with it.
- * </p>
- * <p>
- * e.g. vCard 3.0 does not allow "CHARSET" attribute, but some actual files
- * have it and they uses non UTF-8 charsets. UTF-8 is recommended in RFC 2426,
- * but it is not a must. We silently allow "CHARSET".
- * </p>
- */
-public class VCardParser_V30 implements VCardParser {
-    /* package */ static final Set<String> sKnownPropertyNameSet =
-            Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
-                    "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND", 
-                    "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
-                    "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
-                    "NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
-                    "SORT-STRING", "CATEGORIES", "PRODID"))); // 3.0
-
-    /**
-     * <p>
-     * A unmodifiable Set storing the values for the type "ENCODING", available in the vCard 3.0.
-     * </p>
-     * <p>
-     * Though vCard 2.1 specification does not allow "7BIT" or "BASE64", we allow them for safety.
-     * </p>
-     * <p>
-     * "QUOTED-PRINTABLE" is not allowed in vCard 3.0 and not in this parser either,
-     * because the encoding ambiguates how the vCard file to be parsed.
-     * </p>
-     */
-    /* package */ static final Set<String> sAcceptableEncoding =
-            Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
-                    VCardConstants.PARAM_ENCODING_7BIT,
-                    VCardConstants.PARAM_ENCODING_8BIT,
-                    VCardConstants.PARAM_ENCODING_BASE64,
-                    VCardConstants.PARAM_ENCODING_B)));
-
-    private final VCardParserImpl_V30 mVCardParserImpl;
-
-    public VCardParser_V30() {
-        mVCardParserImpl = new VCardParserImpl_V30();
-    }
-
-    public VCardParser_V30(int vcardType) {
-        mVCardParserImpl = new VCardParserImpl_V30(vcardType);
-    }
-
-    public void parse(InputStream is, VCardInterpreter interepreter)
-            throws IOException, VCardException {
-        mVCardParserImpl.parse(is, interepreter);
-    }
-
-    public void cancel() {
-        mVCardParserImpl.cancel();
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardSourceDetector.java b/vcard/java/com/android/vcard/VCardSourceDetector.java
deleted file mode 100644
index e70d496..0000000
--- a/vcard/java/com/android/vcard/VCardSourceDetector.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import android.text.TextUtils;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * <p>
- * The class which tries to detects the source of a vCard file from its contents.
- * </p>
- * <p>
- * The specification of vCard (including both 2.1 and 3.0) is not so strict as to
- * guess its format just by reading beginning few lines (usually we can, but in
- * some most pessimistic case, we cannot until at almost the end of the file).
- * Also we cannot store all vCard entries in memory, while there's no specification
- * how big the vCard entry would become after the parse.
- * </p>
- * <p>
- * This class is usually used for the "first scan", in which we can understand which vCard
- * version is used (and how many entries exist in a file).
- * </p>
- */
-public class VCardSourceDetector implements VCardInterpreter {
-    private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
-            "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
-            "X-ABADR", "X-ABUID"));
-    
-    private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
-            "X-GNO", "X-GN", "X-REDUCTION"));
-    
-    private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
-            "X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC"));
-    
-    // Note: these signes appears before the signs of the other type (e.g. "X-GN").
-    // In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES.
-    private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList(
-            "X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED",
-            "X-SD-DESCRIPTION"));
-    private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
-
-
-    // TODO: Should replace this with types in VCardConfig
-    private static final int PARSE_TYPE_UNKNOWN = 0;
-    // For Apple's software, which does not mean this type is effective for all its products.
-    // We confirmed they usually use UTF-8, but not sure about vCard type.
-    private static final int PARSE_TYPE_APPLE = 1;
-    // For Japanese mobile phones, which are usually using Shift_JIS as a charset.
-    private static final int PARSE_TYPE_MOBILE_PHONE_JP = 2;
-    // For some of mobile phones released from DoCoMo, which use nested vCard. 
-    private static final int PARSE_TYPE_DOCOMO_TORELATE_NEST = 3;
-    // For Japanese Windows Mobel phones. It's version is supposed to be 6.5.
-    private static final int PARSE_TYPE_WINDOWS_MOBILE_V65_JP = 4;
-
-    private int mParseType = 0;  // Not sure.
-
-    // Some mobile phones (like FOMA) tells us the charset of the data.
-    private boolean mNeedParseSpecifiedCharset;
-    private String mSpecifiedCharset;
-    
-    public void start() {
-    }
-    
-    public void end() {
-    }
-
-    public void startEntry() {
-    }    
-
-    public void startProperty() {
-        mNeedParseSpecifiedCharset = false;
-    }
-    
-    public void endProperty() {
-    }
-
-    public void endEntry() {
-    }
-
-    public void propertyGroup(String group) {
-    }
-    
-    public void propertyName(String name) {
-        if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
-            mParseType = PARSE_TYPE_DOCOMO_TORELATE_NEST;
-            // Probably Shift_JIS is used, but we should double confirm.
-            mNeedParseSpecifiedCharset = true;
-            return;
-        }
-        if (mParseType != PARSE_TYPE_UNKNOWN) {
-            return;
-        }
-        if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) {
-            mParseType = PARSE_TYPE_WINDOWS_MOBILE_V65_JP;
-        } else if (FOMA_SIGNS.contains(name)) {
-            mParseType = PARSE_TYPE_DOCOMO_TORELATE_NEST;
-        } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) {
-            mParseType = PARSE_TYPE_MOBILE_PHONE_JP;
-        } else if (APPLE_SIGNS.contains(name)) {
-            mParseType = PARSE_TYPE_APPLE;
-        }
-    }
-
-    public void propertyParamType(String type) {
-    }
-
-    public void propertyParamValue(String value) {
-    }
-
-    public void propertyValues(List<String> values) {
-        if (mNeedParseSpecifiedCharset && values.size() > 0) {
-            mSpecifiedCharset = values.get(0);
-        }
-    }
-
-    /**
-     * @return The available type can be used with vCard parser. You probably need to
-     * use {{@link #getEstimatedCharset()} to understand the charset to be used.
-     */
-    public int getEstimatedType() {
-        switch (mParseType) {
-            case PARSE_TYPE_DOCOMO_TORELATE_NEST:
-                return VCardConfig.VCARD_TYPE_DOCOMO | VCardConfig.FLAG_TORELATE_NEST;
-            case PARSE_TYPE_MOBILE_PHONE_JP:
-                return VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE;
-            case PARSE_TYPE_APPLE:
-            case PARSE_TYPE_WINDOWS_MOBILE_V65_JP:
-            default:
-                return VCardConfig.VCARD_TYPE_UNKNOWN;
-        }
-    }
-
-    /**
-     * <p>
-     * Returns charset String guessed from the source's properties.
-     * This method must be called after parsing target file(s).
-     * </p>
-     * @return Charset String. Null is returned if guessing the source fails.
-     */
-    public String getEstimatedCharset() {
-        if (TextUtils.isEmpty(mSpecifiedCharset)) {
-            return mSpecifiedCharset;
-        }
-        switch (mParseType) {
-            case PARSE_TYPE_WINDOWS_MOBILE_V65_JP:
-            case PARSE_TYPE_DOCOMO_TORELATE_NEST:
-            case PARSE_TYPE_MOBILE_PHONE_JP:
-                return "SHIFT_JIS";
-            case PARSE_TYPE_APPLE:
-                return "UTF-8";
-            default:
-                return null;
-        }
-    }
-}
diff --git a/vcard/java/com/android/vcard/VCardUtils.java b/vcard/java/com/android/vcard/VCardUtils.java
deleted file mode 100644
index fb0c2e7..0000000
--- a/vcard/java/com/android/vcard/VCardUtils.java
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.net.QuotedPrintableCodec;
-
-import android.content.ContentProviderOperation;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Utilities for VCard handling codes.
- */
-public class VCardUtils {
-    private static final String LOG_TAG = "VCardUtils";
-
-    // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
-    // converted to two parameter Strings. These only contain some minor fields valid in both
-    // vCard and current (as of 2009-08-07) Contacts structure. 
-    private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
-    private static final Set<String> sPhoneTypesUnknownToContactsSet;
-    private static final Map<String, Integer> sKnownPhoneTypeMap_StoI;
-    private static final Map<Integer, String> sKnownImPropNameMap_ItoS;
-    private static final Set<String> sMobilePhoneLabelSet;
-
-    static {
-        sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
-        sKnownPhoneTypeMap_StoI = new HashMap<String, Integer>();
-
-        sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, VCardConstants.PARAM_TYPE_CAR);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CAR, Phone.TYPE_CAR);
-        sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, VCardConstants.PARAM_TYPE_PAGER);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_PAGER, Phone.TYPE_PAGER);
-        sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, VCardConstants.PARAM_TYPE_ISDN);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_ISDN, Phone.TYPE_ISDN);
-        
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_HOME, Phone.TYPE_HOME);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_WORK, Phone.TYPE_WORK);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CELL, Phone.TYPE_MOBILE);
-                
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_CALLBACK,
-                Phone.TYPE_CALLBACK);
-        sKnownPhoneTypeMap_StoI.put(
-                VCardConstants.PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_TTY_TDD,
-                Phone.TYPE_TTY_TDD);
-        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_ASSISTANT,
-                Phone.TYPE_ASSISTANT);
-
-        sPhoneTypesUnknownToContactsSet = new HashSet<String>();
-        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MODEM);
-        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MSG);
-        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_BBS);
-        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_VIDEO);
-
-        sKnownImPropNameMap_ItoS = new HashMap<Integer, String>();
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_GOOGLE_TALK,
-                VCardConstants.PROPERTY_X_GOOGLE_TALK);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, VCardConstants.PROPERTY_X_QQ);
-        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, VCardConstants.PROPERTY_X_NETMEETING);
-
-        // \u643A\u5E2F\u96FB\u8A71 = Full-width Hiragana "Keitai-Denwa" (mobile phone)
-        // \u643A\u5E2F = Full-width Hiragana "Keitai" (mobile phone)
-        // \u30B1\u30A4\u30BF\u30A4 = Full-width Katakana "Keitai" (mobile phone)
-        // \uFF79\uFF72\uFF80\uFF72 = Half-width Katakana "Keitai" (mobile phone)
-        sMobilePhoneLabelSet = new HashSet<String>(Arrays.asList(
-                "MOBILE", "\u643A\u5E2F\u96FB\u8A71", "\u643A\u5E2F", "\u30B1\u30A4\u30BF\u30A4",
-                "\uFF79\uFF72\uFF80\uFF72"));
-    }
-
-    public static String getPhoneTypeString(Integer type) {
-        return sKnownPhoneTypesMap_ItoS.get(type);
-    }
-
-    /**
-     * Returns Interger when the given types can be parsed as known type. Returns String object
-     * when not, which should be set to label. 
-     */
-    public static Object getPhoneTypeFromStrings(Collection<String> types,
-            String number) {
-        if (number == null) {
-            number = "";
-        }
-        int type = -1;
-        String label = null;
-        boolean isFax = false;
-        boolean hasPref = false;
-        
-        if (types != null) {
-            for (String typeString : types) {
-                if (typeString == null) {
-                    continue;
-                }
-                typeString = typeString.toUpperCase();
-                if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
-                    hasPref = true;
-                } else if (typeString.equals(VCardConstants.PARAM_TYPE_FAX)) {
-                    isFax = true;
-                } else {
-                    if (typeString.startsWith("X-") && type < 0) {
-                        typeString = typeString.substring(2);
-                    }
-                    if (typeString.length() == 0) {
-                        continue;
-                    }
-                    final Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
-                    if (tmp != null) {
-                        final int typeCandidate = tmp;
-                        // TYPE_PAGER is prefered when the number contains @ surronded by
-                        // a pager number and a domain name.
-                        // e.g.
-                        // o 1111@domain.com
-                        // x @domain.com
-                        // x 1111@
-                        final int indexOfAt = number.indexOf("@");
-                        if ((typeCandidate == Phone.TYPE_PAGER
-                                && 0 < indexOfAt && indexOfAt < number.length() - 1)
-                                || type < 0
-                                || type == Phone.TYPE_CUSTOM) {
-                            type = tmp;
-                        }
-                    } else if (type < 0) {
-                        type = Phone.TYPE_CUSTOM;
-                        label = typeString;
-                    }
-                }
-            }
-        }
-        if (type < 0) {
-            if (hasPref) {
-                type = Phone.TYPE_MAIN;
-            } else {
-                // default to TYPE_HOME
-                type = Phone.TYPE_HOME;
-            }
-        }
-        if (isFax) {
-            if (type == Phone.TYPE_HOME) {
-                type = Phone.TYPE_FAX_HOME;
-            } else if (type == Phone.TYPE_WORK) {
-                type = Phone.TYPE_FAX_WORK;
-            } else if (type == Phone.TYPE_OTHER) {
-                type = Phone.TYPE_OTHER_FAX;
-            }
-        }
-        if (type == Phone.TYPE_CUSTOM) {
-            return label;
-        } else {
-            return type;
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    public static boolean isMobilePhoneLabel(final String label) {
-        // For backward compatibility.
-        // Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now.
-        //         To support mobile type at that time, this custom label had been used.
-        return ("_AUTO_CELL".equals(label) || sMobilePhoneLabelSet.contains(label));
-    }
-
-    public static boolean isValidInV21ButUnknownToContactsPhoteType(final String label) {
-        return sPhoneTypesUnknownToContactsSet.contains(label);
-    }
-
-    public static String getPropertyNameForIm(final int protocol) {
-        return sKnownImPropNameMap_ItoS.get(protocol);
-    }
-
-    public static String[] sortNameElements(final int vcardType,
-            final String familyName, final String middleName, final String givenName) {
-        final String[] list = new String[3];
-        final int nameOrderType = VCardConfig.getNameOrderType(vcardType);
-        switch (nameOrderType) {
-            case VCardConfig.NAME_ORDER_JAPANESE: {
-                if (containsOnlyPrintableAscii(familyName) &&
-                        containsOnlyPrintableAscii(givenName)) {
-                    list[0] = givenName;
-                    list[1] = middleName;
-                    list[2] = familyName;
-                } else {
-                    list[0] = familyName;
-                    list[1] = middleName;
-                    list[2] = givenName;
-                }
-                break;
-            }
-            case VCardConfig.NAME_ORDER_EUROPE: {
-                list[0] = middleName;
-                list[1] = givenName;
-                list[2] = familyName;
-                break;
-            }
-            default: {
-                list[0] = givenName;
-                list[1] = middleName;
-                list[2] = familyName;
-                break;
-            }
-        }
-        return list;
-    }
-
-    public static int getPhoneNumberFormat(final int vcardType) {
-        if (VCardConfig.isJapaneseDevice(vcardType)) {
-            return PhoneNumberUtils.FORMAT_JAPAN;
-        } else {
-            return PhoneNumberUtils.FORMAT_NANP;
-        }
-    }
-
-    /**
-     * <p>
-     * Inserts postal data into the builder object.
-     * </p>
-     * <p>
-     * Note that the data structure of ContactsContract is different from that defined in vCard.
-     * So some conversion may be performed in this method.
-     * </p>
-     */
-    public static void insertStructuredPostalDataUsingContactsStruct(int vcardType,
-            final ContentProviderOperation.Builder builder,
-            final VCardEntry.PostalData postalData) {
-        builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0);
-        builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
-
-        builder.withValue(StructuredPostal.TYPE, postalData.type);
-        if (postalData.type == StructuredPostal.TYPE_CUSTOM) {
-            builder.withValue(StructuredPostal.LABEL, postalData.label);
-        }
-
-        final String streetString;
-        if (TextUtils.isEmpty(postalData.street)) {
-            if (TextUtils.isEmpty(postalData.extendedAddress)) {
-                streetString = null;
-            } else {
-                streetString = postalData.extendedAddress;
-            }
-        } else {
-            if (TextUtils.isEmpty(postalData.extendedAddress)) {
-                streetString = postalData.street;
-            } else {
-                streetString = postalData.street + " " + postalData.extendedAddress;
-            }
-        }
-        builder.withValue(StructuredPostal.POBOX, postalData.pobox);
-        builder.withValue(StructuredPostal.STREET, streetString);
-        builder.withValue(StructuredPostal.CITY, postalData.localty);
-        builder.withValue(StructuredPostal.REGION, postalData.region);
-        builder.withValue(StructuredPostal.POSTCODE, postalData.postalCode);
-        builder.withValue(StructuredPostal.COUNTRY, postalData.country);
-
-        builder.withValue(StructuredPostal.FORMATTED_ADDRESS,
-                postalData.getFormattedAddress(vcardType));
-        if (postalData.isPrimary) {
-            builder.withValue(Data.IS_PRIMARY, 1);
-        }
-    }
-
-    public static String constructNameFromElements(final int vcardType,
-            final String familyName, final String middleName, final String givenName) {
-        return constructNameFromElements(vcardType, familyName, middleName, givenName,
-                null, null);
-    }
-
-    public static String constructNameFromElements(final int vcardType,
-            final String familyName, final String middleName, final String givenName,
-            final String prefix, final String suffix) {
-        final StringBuilder builder = new StringBuilder();
-        final String[] nameList = sortNameElements(vcardType, familyName, middleName, givenName);
-        boolean first = true;
-        if (!TextUtils.isEmpty(prefix)) {
-            first = false;
-            builder.append(prefix);
-        }
-        for (final String namePart : nameList) {
-            if (!TextUtils.isEmpty(namePart)) {
-                if (first) {
-                    first = false;
-                } else {
-                    builder.append(' ');
-                }
-                builder.append(namePart);
-            }
-        }
-        if (!TextUtils.isEmpty(suffix)) {
-            if (!first) {
-                builder.append(' ');
-            }
-            builder.append(suffix);
-        }
-        return builder.toString();
-    }
-
-    public static List<String> constructListFromValue(final String value,
-            final boolean isV30) {
-        final List<String> list = new ArrayList<String>();
-        StringBuilder builder = new StringBuilder();
-        int length = value.length();
-        for (int i = 0; i < length; i++) {
-            char ch = value.charAt(i);
-            if (ch == '\\' && i < length - 1) {
-                char nextCh = value.charAt(i + 1);
-                final String unescapedString =
-                    (isV30 ? VCardParserImpl_V30.unescapeCharacter(nextCh) :
-                        VCardParserImpl_V21.unescapeCharacter(nextCh));
-                if (unescapedString != null) {
-                    builder.append(unescapedString);
-                    i++;
-                } else {
-                    builder.append(ch);
-                }
-            } else if (ch == ';') {
-                list.add(builder.toString());
-                builder = new StringBuilder();
-            } else {
-                builder.append(ch);
-            }
-        }
-        list.add(builder.toString());
-        return list;
-    }
-
-    public static boolean containsOnlyPrintableAscii(final String...values) {
-        if (values == null) {
-            return true;
-        }
-        return containsOnlyPrintableAscii(Arrays.asList(values));
-    }
-
-    public static boolean containsOnlyPrintableAscii(final Collection<String> values) {
-        if (values == null) {
-            return true;
-        }
-        for (final String value : values) {
-            if (TextUtils.isEmpty(value)) {
-                continue;
-            }
-            if (!TextUtils.isPrintableAsciiOnly(value)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * <p>
-     * This is useful when checking the string should be encoded into quoted-printable
-     * or not, which is required by vCard 2.1.
-     * </p>
-     * <p>
-     * See the definition of "7bit" in vCard 2.1 spec for more information.
-     * </p>
-     */
-    public static boolean containsOnlyNonCrLfPrintableAscii(final String...values) {
-        if (values == null) {
-            return true;
-        }
-        return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values));
-    }
-
-    public static boolean containsOnlyNonCrLfPrintableAscii(final Collection<String> values) {
-        if (values == null) {
-            return true;
-        }
-        final int asciiFirst = 0x20;
-        final int asciiLast = 0x7E;  // included
-        for (final String value : values) {
-            if (TextUtils.isEmpty(value)) {
-                continue;
-            }
-            final int length = value.length();
-            for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
-                final int c = value.codePointAt(i);
-                if (!(asciiFirst <= c && c <= asciiLast)) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    private static final Set<Character> sUnAcceptableAsciiInV21WordSet =
-        new HashSet<Character>(Arrays.asList('[', ']', '=', ':', '.', ',', ' '));
-
-    /**
-     * <p>
-     * This is useful since vCard 3.0 often requires the ("X-") properties and groups
-     * should contain only alphabets, digits, and hyphen.
-     * </p>
-     * <p> 
-     * Note: It is already known some devices (wrongly) outputs properties with characters
-     *       which should not be in the field. One example is "X-GOOGLE TALK". We accept
-     *       such kind of input but must never output it unless the target is very specific
-     *       to the device which is able to parse the malformed input.
-     * </p>
-     */
-    public static boolean containsOnlyAlphaDigitHyphen(final String...values) {
-        if (values == null) {
-            return true;
-        }
-        return containsOnlyAlphaDigitHyphen(Arrays.asList(values));
-    }
-
-    public static boolean containsOnlyAlphaDigitHyphen(final Collection<String> values) {
-        if (values == null) {
-            return true;
-        }
-        final int upperAlphabetFirst = 0x41;  // A
-        final int upperAlphabetAfterLast = 0x5b;  // [
-        final int lowerAlphabetFirst = 0x61;  // a
-        final int lowerAlphabetAfterLast = 0x7b;  // {
-        final int digitFirst = 0x30;  // 0
-        final int digitAfterLast = 0x3A;  // :
-        final int hyphen = '-';
-        for (final String str : values) {
-            if (TextUtils.isEmpty(str)) {
-                continue;
-            }
-            final int length = str.length();
-            for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
-                int codepoint = str.codePointAt(i);
-                if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) ||
-                    (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) ||
-                    (digitFirst <= codepoint && codepoint < digitAfterLast) ||
-                    (codepoint == hyphen))) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * <p>
-     * Returns true when the given String is categorized as "word" specified in vCard spec 2.1.
-     * </p>
-     * <p>
-     * vCard 2.1 specifies:<br />
-     * word = &lt;any printable 7bit us-ascii except []=:., &gt;
-     * </p>
-     */
-    public static boolean isV21Word(final String value) {
-        if (TextUtils.isEmpty(value)) {
-            return true;
-        }
-        final int asciiFirst = 0x20;
-        final int asciiLast = 0x7E;  // included
-        final int length = value.length();
-        for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
-            final int c = value.codePointAt(i);
-            if (!(asciiFirst <= c && c <= asciiLast) ||
-                    sUnAcceptableAsciiInV21WordSet.contains((char)c)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public static String toHalfWidthString(final String orgString) {
-        if (TextUtils.isEmpty(orgString)) {
-            return null;
-        }
-        final StringBuilder builder = new StringBuilder();
-        final int length = orgString.length();
-        for (int i = 0; i < length; i = orgString.offsetByCodePoints(i, 1)) {
-            // All Japanese character is able to be expressed by char.
-            // Do not need to use String#codepPointAt().
-            final char ch = orgString.charAt(i);
-            final String halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
-            if (halfWidthText != null) {
-                builder.append(halfWidthText);
-            } else {
-                builder.append(ch);
-            }
-        }
-        return builder.toString();
-    }
-
-    /**
-     * Guesses the format of input image. Currently just the first few bytes are used.
-     * The type "GIF", "PNG", or "JPEG" is returned when possible. Returns null when
-     * the guess failed.
-     * @param input Image as byte array.
-     * @return The image type or null when the type cannot be determined.
-     */
-    public static String guessImageType(final byte[] input) {
-        if (input == null) {
-            return null;
-        }
-        if (input.length >= 3 && input[0] == 'G' && input[1] == 'I' && input[2] == 'F') {
-            return "GIF";
-        } else if (input.length >= 4 && input[0] == (byte) 0x89
-                && input[1] == 'P' && input[2] == 'N' && input[3] == 'G') {
-            // Note: vCard 2.1 officially does not support PNG, but we may have it and
-            //       using X- word like "X-PNG" may not let importers know it is PNG.
-            //       So we use the String "PNG" as is...
-            return "PNG";
-        } else if (input.length >= 2 && input[0] == (byte) 0xff
-                && input[1] == (byte) 0xd8) {
-            return "JPEG";
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * @return True when all the given values are null or empty Strings.
-     */
-    public static boolean areAllEmpty(final String...values) {
-        if (values == null) {
-            return true;
-        }
-
-        for (final String value : values) {
-            if (!TextUtils.isEmpty(value)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    //// The methods bellow may be used by unit test.
-
-    /**
-     * @hide 
-     */
-    public static String parseQuotedPrintable(String value, boolean strictLineBreaking,
-            String sourceCharset, String targetCharset) {
-        // "= " -> " ", "=\t" -> "\t".
-        // Previous code had done this replacement. Keep on the safe side.
-        final String quotedPrintable;
-        {
-            final StringBuilder builder = new StringBuilder();
-            final int length = value.length();
-            for (int i = 0; i < length; i++) {
-                char ch = value.charAt(i);
-                if (ch == '=' && i < length - 1) {
-                    char nextCh = value.charAt(i + 1);
-                    if (nextCh == ' ' || nextCh == '\t') {
-                        builder.append(nextCh);
-                        i++;
-                        continue;
-                    }
-                }
-                builder.append(ch);
-            }
-            quotedPrintable = builder.toString();
-        }
-
-        String[] lines;
-        if (strictLineBreaking) {
-            lines = quotedPrintable.split("\r\n");
-        } else {
-            StringBuilder builder = new StringBuilder();
-            final int length = quotedPrintable.length();
-            ArrayList<String> list = new ArrayList<String>();
-            for (int i = 0; i < length; i++) {
-                char ch = quotedPrintable.charAt(i);
-                if (ch == '\n') {
-                    list.add(builder.toString());
-                    builder = new StringBuilder();
-                } else if (ch == '\r') {
-                    list.add(builder.toString());
-                    builder = new StringBuilder();
-                    if (i < length - 1) {
-                        char nextCh = quotedPrintable.charAt(i + 1);
-                        if (nextCh == '\n') {
-                            i++;
-                        }
-                    }
-                } else {
-                    builder.append(ch);
-                }
-            }
-            final String lastLine = builder.toString();
-            if (lastLine.length() > 0) {
-                list.add(lastLine);
-            }
-            lines = list.toArray(new String[0]);
-        }
-
-        final StringBuilder builder = new StringBuilder();
-        for (String line : lines) {
-            if (line.endsWith("=")) {
-                line = line.substring(0, line.length() - 1);
-            }
-            builder.append(line);
-        }
-
-        final String rawString = builder.toString();
-        if (TextUtils.isEmpty(rawString)) {
-            Log.w(LOG_TAG, "Given raw string is empty.");
-        }
-
-        byte[] rawBytes = null;
-        try {
-            rawBytes = rawString.getBytes(sourceCharset); 
-        } catch (UnsupportedEncodingException e) {
-            Log.w(LOG_TAG, "Failed to decode: " + sourceCharset);
-            rawBytes = rawString.getBytes();
-        }
-
-        byte[] decodedBytes = null;
-        try {
-            decodedBytes = QuotedPrintableCodec.decodeQuotedPrintable(rawBytes);
-        } catch (DecoderException e) {
-            Log.e(LOG_TAG, "DecoderException is thrown.");
-            decodedBytes = rawBytes;
-        }
-
-        try {
-            return new String(decodedBytes, targetCharset);
-        } catch (UnsupportedEncodingException e) {
-            Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
-            return new String(decodedBytes);
-        }
-    }
-
-    private VCardUtils() {
-    }
-}
diff --git a/vcard/java/com/android/vcard/exception/VCardAgentNotSupportedException.java b/vcard/java/com/android/vcard/exception/VCardAgentNotSupportedException.java
deleted file mode 100644
index c408716..0000000
--- a/vcard/java/com/android/vcard/exception/VCardAgentNotSupportedException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.exception;
-
-public class VCardAgentNotSupportedException extends VCardNotSupportedException {
-    public VCardAgentNotSupportedException() {
-        super();
-    }
-
-    public VCardAgentNotSupportedException(String message) {
-        super(message);
-    }
-
-}
\ No newline at end of file
diff --git a/vcard/java/com/android/vcard/exception/VCardException.java b/vcard/java/com/android/vcard/exception/VCardException.java
deleted file mode 100644
index 3ad7fd3..0000000
--- a/vcard/java/com/android/vcard/exception/VCardException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.exception;
-
-public class VCardException extends java.lang.Exception {
-    /**
-     * Constructs a VCardException object
-     */
-    public VCardException() {
-        super();
-    }
-
-    /**
-     * Constructs a VCardException object
-     *
-     * @param message the error message
-     */
-    public VCardException(String message) {
-        super(message);
-    }
-
-}
diff --git a/vcard/java/com/android/vcard/exception/VCardInvalidCommentLineException.java b/vcard/java/com/android/vcard/exception/VCardInvalidCommentLineException.java
deleted file mode 100644
index 342769e..0000000
--- a/vcard/java/com/android/vcard/exception/VCardInvalidCommentLineException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.vcard.exception;
-
-/**
- * Thrown when the vCard has some line starting with '#'. In the specification,
- * both vCard 2.1 and vCard 3.0 does not allow such line, but some actual exporter emit
- * such lines.
- */
-public class VCardInvalidCommentLineException extends VCardInvalidLineException {
-    public VCardInvalidCommentLineException() {
-        super();
-    }
-
-    public VCardInvalidCommentLineException(final String message) {
-        super(message);
-    }
-}
diff --git a/vcard/java/com/android/vcard/exception/VCardInvalidLineException.java b/vcard/java/com/android/vcard/exception/VCardInvalidLineException.java
deleted file mode 100644
index 5c2250f..0000000
--- a/vcard/java/com/android/vcard/exception/VCardInvalidLineException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.exception;
-
-/**
- * Thrown when the vCard has some line starting with '#'. In the specification,
- * both vCard 2.1 and vCard 3.0 does not allow such line, but some actual exporter emit
- * such lines.
- */
-public class VCardInvalidLineException extends VCardException {
-    public VCardInvalidLineException() {
-        super();
-    }
-
-    public VCardInvalidLineException(final String message) {
-        super(message);
-    }
-}
diff --git a/vcard/java/com/android/vcard/exception/VCardNestedException.java b/vcard/java/com/android/vcard/exception/VCardNestedException.java
deleted file mode 100644
index 2b9b1ac..0000000
--- a/vcard/java/com/android/vcard/exception/VCardNestedException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.vcard.exception;
-
-/**
- * VCardException thrown when VCard is nested without VCardParser's being notified.
- */
-public class VCardNestedException extends VCardNotSupportedException {
-    public VCardNestedException() {
-        super();
-    }
-    public VCardNestedException(String message) {
-        super(message);
-    }
-}
diff --git a/vcard/java/com/android/vcard/exception/VCardNotSupportedException.java b/vcard/java/com/android/vcard/exception/VCardNotSupportedException.java
deleted file mode 100644
index 61ff752..0000000
--- a/vcard/java/com/android/vcard/exception/VCardNotSupportedException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.exception;
-
-/**
- * The exception which tells that the input VCard is probably valid from the view of
- * specification but not supported in the current framework for now.
- * 
- * This is a kind of a good news from the view of development.
- * It may be good to ask users to send a report with the VCard example
- * for the future development.
- */
-public class VCardNotSupportedException extends VCardException {
-    public VCardNotSupportedException() {
-        super();
-    }
-    public VCardNotSupportedException(String message) {
-        super(message);
-    }
-}
\ No newline at end of file
diff --git a/vcard/java/com/android/vcard/exception/VCardVersionException.java b/vcard/java/com/android/vcard/exception/VCardVersionException.java
deleted file mode 100644
index 047c580..0000000
--- a/vcard/java/com/android/vcard/exception/VCardVersionException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.exception;
-
-/**
- * VCardException used only when the version of the vCard is different. 
- */
-public class VCardVersionException extends VCardException {
-    public VCardVersionException() {
-        super();
-    }
-    public VCardVersionException(String message) {
-        super(message);
-    }
-}
diff --git a/vcard/tests/Android.mk b/vcard/tests/Android.mk
deleted file mode 100644
index 853ee14..0000000
--- a/vcard/tests/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := AndroidVCardTests
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner google-common
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.vcard
-
-include $(BUILD_PACKAGE)
diff --git a/vcard/tests/AndroidManifest.xml b/vcard/tests/AndroidManifest.xml
deleted file mode 100644
index fcbf767..0000000
--- a/vcard/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.vcard.tests"
-        android:sharedUserId="com.android.uid.test">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <!-- Run tests with "runtest common" -->
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="com.android.vcard.tests"
-            android:label="Android vCard Library Tests" />
-
-</manifest>
diff --git a/vcard/tests/res/raw/v21_backslash.vcf b/vcard/tests/res/raw/v21_backslash.vcf
deleted file mode 100644
index bd3002b..0000000
--- a/vcard/tests/res/raw/v21_backslash.vcf
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-N:;A\;B\\;C\\\;;D;\:E;\\\\;

-FN:A;B\C\;D:E\\

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_complicated.vcf b/vcard/tests/res/raw/v21_complicated.vcf
deleted file mode 100644
index de34e16..0000000
--- a/vcard/tests/res/raw/v21_complicated.vcf
+++ /dev/null
@@ -1,106 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-N:Gump;Forrest;Hoge;Pos;Tao

-FN:Joe Due

-ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper

-ROLE:Fish Cake Keeper!

-X-CLASS:PUBLIC

-TITLE:Shrimp Man

-TEL;WORK;VOICE:(111) 555-1212

-TEL;HOME;VOICE:(404) 555-1212

-TEL;CELL:0311111111

-TEL;VIDEO:0322222222

-TEL;VOICE:0333333333

-ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America

-LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited  States of America

-ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America

-LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=

-Baytown, LA 30314=0D=0A=

-United  States of America

-EMAIL;PREF;INTERNET:forrestgump@walladalla.com

-EMAIL;CELL:cell@example.com

-NOTE:The following note is the example from RFC 2045.

-NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =

-for all folk to come=

- to the aid of their country.

-

-PHOTO;ENCODING=BASE64;TYPE=JPEG:

- /9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG

- AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx

- AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB

- AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI

- AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg

- ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ

- gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA

- AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA

- AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA

- kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA

- AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK

- knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA

- AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw

- ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA

- AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA

- pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA

- AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1

- OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA

- AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA

- AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA

- ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA

- AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww

- YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe

- xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG

- /8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA

- AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK

- FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG

- h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl

- 5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH

- BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka

- JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT

- lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz

- 9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF

- ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA

- RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD

- ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx

- qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a

- oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU

- WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA

- c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB

- Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N

- SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT

- DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA

- GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm

- mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w

- 0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT

- SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN

- PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI

- CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9

- PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7

- Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA

- AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC

- scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp

- anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS

- 09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI

- CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi

- ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4

- eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY

- 2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX

- SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc

- UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc

- 0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H

- urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks

- puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3

- JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m

- 6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT

- 9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe

- ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv

- LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2

- SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a

- IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt

- zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z

-

-X-ATTRIBUTE:Some String

-BDAY:19800101

-GEO:35.6563854,139.6994233

-URL:http://www.example.com/

-REV:20080424T195243Z

-END:VCARD
\ No newline at end of file
diff --git a/vcard/tests/res/raw/v21_invalid_comment_line.vcf b/vcard/tests/res/raw/v21_invalid_comment_line.vcf
deleted file mode 100644
index f910710..0000000
--- a/vcard/tests/res/raw/v21_invalid_comment_line.vcf
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN:vCard

-VERSION:2.1

-UID:357

-N:;Conference Call

-FN:Conference Call

-# This line must be ignored.

-NOTE;ENCODING=QUOTED-PRINTABLE:This is an (sharp ->=

-#<- sharp) example. This message must NOT be ignored.

-# This line must be ignored too.

-END:vCard

diff --git a/vcard/tests/res/raw/v21_japanese_1.vcf b/vcard/tests/res/raw/v21_japanese_1.vcf
deleted file mode 100644
index d05e2ff..0000000
--- a/vcard/tests/res/raw/v21_japanese_1.vcf
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh;;;;

-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ;;;;

-TEL;PREF;VOICE:0300000000

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_japanese_2.vcf b/vcard/tests/res/raw/v21_japanese_2.vcf
deleted file mode 100644
index fa54acb..0000000
--- a/vcard/tests/res/raw/v21_japanese_2.vcf
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-FN;CHARSET=SHIFT_JIS:ˆÀ“¡ ƒƒCƒh 1

-N;CHARSET=SHIFT_JIS:ˆÀ“¡;ƒƒCƒh1;;;

-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³;Û²ÄÞ1;;;

-ADR;HOME;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:;=93=8C=8B=9E=93=73=

-=8F=61=92=4A=8B=E6=8D=F7=8B=75=92=AC26-1=83=5A=83=8B=83=8A=83=41=83=93=

-=83=5E=83=8F=81=5B6=8A=4B;;;;150-8512;

-NOTE;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:=83=81=83=82

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_multiple_entry.vcf b/vcard/tests/res/raw/v21_multiple_entry.vcf
deleted file mode 100644
index ebbb19a..0000000
--- a/vcard/tests/res/raw/v21_multiple_entry.vcf
+++ /dev/null
@@ -1,33 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh3;;;;

-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ3;;;;

-TEL;X-NEC-SECRET:9

-TEL;X-NEC-HOTEL:10

-TEL;X-NEC-SCHOOL:11

-TEL;HOME;FAX:12

-END:VCARD

-

-

-BEGIN:VCARD

-VERSION:2.1

-N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh4;;;;

-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ4;;;;

-TEL;MODEM:13

-TEL;PAGER:14

-TEL;X-NEC-FAMILY:15

-TEL;X-NEC-GIRL:16

-END:VCARD

-

-

-BEGIN:VCARD

-VERSION:2.1

-N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh5;;;;

-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ5;;;;

-TEL;X-NEC-BOY:17

-TEL;X-NEC-FRIEND:18

-TEL;X-NEC-PHS:19

-TEL;X-NEC-RESTAURANT:20

-END:VCARD

-

-

diff --git a/vcard/tests/res/raw/v21_org_before_title.vcf b/vcard/tests/res/raw/v21_org_before_title.vcf
deleted file mode 100644
index 8ff1190..0000000
--- a/vcard/tests/res/raw/v21_org_before_title.vcf
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-FN:Normal Guy

-ORG:Company;Organization;Devision;Room;Sheet No.

-TITLE:Excellent Janitor

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_pref_handling.vcf b/vcard/tests/res/raw/v21_pref_handling.vcf
deleted file mode 100644
index 5105310..0000000
--- a/vcard/tests/res/raw/v21_pref_handling.vcf
+++ /dev/null
@@ -1,15 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-FN:Smith
-TEL;HOME:1
-TEL;WORK;PREF:2
-TEL;ISDN:3
-EMAIL;PREF;HOME:test@example.com
-EMAIL;CELL;PREF:test2@examination.com
-ORG:Company
-TITLE:Engineer
-ORG:Mystery
-TITLE:Blogger
-ORG:Poetry
-TITLE:Poet
-END:VCARD
diff --git a/vcard/tests/res/raw/v21_simple_1.vcf b/vcard/tests/res/raw/v21_simple_1.vcf
deleted file mode 100644
index 6aabb4c..0000000
--- a/vcard/tests/res/raw/v21_simple_1.vcf
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN:VCARD

-N:Ando;Roid;

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_simple_2.vcf b/vcard/tests/res/raw/v21_simple_2.vcf
deleted file mode 100644
index f0d5ab5..0000000
--- a/vcard/tests/res/raw/v21_simple_2.vcf
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN:VCARD

-FN:Ando Roid

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_simple_3.vcf b/vcard/tests/res/raw/v21_simple_3.vcf
deleted file mode 100644
index beddabb..0000000
--- a/vcard/tests/res/raw/v21_simple_3.vcf
+++ /dev/null
@@ -1,4 +0,0 @@
-BEGIN:VCARD

-N:Ando;Roid;

-FN:Ando Roid

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_title_before_org.vcf b/vcard/tests/res/raw/v21_title_before_org.vcf
deleted file mode 100644
index 9fdc738..0000000
--- a/vcard/tests/res/raw/v21_title_before_org.vcf
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-FN:Nice Guy

-TITLE:Cool Title

-ORG:Marverous;Perfect;Great;Good;Bad;Poor

-END:VCARD

diff --git a/vcard/tests/res/raw/v21_winmo_65.vcf b/vcard/tests/res/raw/v21_winmo_65.vcf
deleted file mode 100644
index f380d0d..0000000
--- a/vcard/tests/res/raw/v21_winmo_65.vcf
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN:VCARD

-VERSION:2.1

-N:Example;;;;

-FN:Example

-ANNIVERSARY;VALUE=DATE:20091010

-AGENT:Invalid line which must be handled correctly.

-X-CLASS:PUBLIC

-X-REDUCTION:

-X-NO:

-END:VCARD

diff --git a/vcard/tests/res/raw/v30_comma_separated.vcf b/vcard/tests/res/raw/v30_comma_separated.vcf
deleted file mode 100644
index 98a7f20..0000000
--- a/vcard/tests/res/raw/v30_comma_separated.vcf
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN:VCARD

-VERSION:3.0

-N:F;G;M;;

-TEL;TYPE=PAGER,WORK,MSG:6101231234@pagersample.com

-END:VCARD

diff --git a/vcard/tests/res/raw/v30_simple.vcf b/vcard/tests/res/raw/v30_simple.vcf
deleted file mode 100644
index 418661f..0000000
--- a/vcard/tests/res/raw/v30_simple.vcf
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN:VCARD

-VERSION:3.0

-FN:And Roid

-N:And;Roid;;;

-ORG:Open;Handset; Alliance

-SORT-STRING:android

-TEL;TYPE=PREF;TYPE=VOICE:0300000000

-CLASS:PUBLIC

-X-GNO:0

-X-GN:group0

-X-REDUCTION:0

-REV:20081031T065854Z

-END:VCARD

diff --git a/vcard/tests/src/com/android/vcard/tests/VCardExporterTests.java b/vcard/tests/src/com/android/vcard/tests/VCardExporterTests.java
deleted file mode 100644
index b6419c3..0000000
--- a/vcard/tests/src/com/android/vcard/tests/VCardExporterTests.java
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.vcard.tests;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.tests.test_utils.ContactEntry;
-import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem;
-import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem.TypeSet;
-
-import java.util.Arrays;
-
-/**
- * Tests for the code related to vCard exporter, inculding vCard composer.
- * This test class depends on vCard importer code, so if tests for vCard importer fail,
- * the result of this class will not be reliable.
- */
-public class VCardExporterTests extends VCardTestsBase {
-    private static final byte[] sPhotoByteArray =
-        VCardImporterTests.sPhotoByteArrayForComplicatedCase;
-
-    public void testSimpleV21() {
-        mVerifier.initForExportTest(V21);
-        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "Ando")
-                .put(StructuredName.GIVEN_NAME, "Roid");
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("FN", "Roid Ando")
-                .addExpectedNode("N", "Ando;Roid;;;",
-                        Arrays.asList("Ando", "Roid", "", "", ""));
-    }
-
-    private void testStructuredNameBasic(int vcardType) {
-        final boolean isV30 = VCardConfig.isV30(vcardType);
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
-                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
-                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
-                .put(StructuredName.PREFIX, "AppropriatePrefix")
-                .put(StructuredName.SUFFIX, "AppropriateSuffix")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
-
-        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("N",
-                        "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
-                        + "AppropriatePrefix;AppropriateSuffix",
-                        Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
-                                "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
-                .addExpectedNodeWithOrder("FN",
-                        "AppropriatePrefix AppropriateGivenName "
-                        + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
-                .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
-                .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
-                .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
-
-        if (isV30) {
-            elem.addExpectedNode("SORT-STRING",
-                    "AppropriatePhoneticGiven AppropriatePhoneticMiddle "
-                    + "AppropriatePhoneticFamily");
-        }
-    }
-
-    public void testStructuredNameBasicV21() {
-        testStructuredNameBasic(V21);
-    }
-
-    public void testStructuredNameBasicV30() {
-        testStructuredNameBasic(V30);
-    }
-
-    /**
-     * Test that only "primary" StructuredName is emitted, so that our vCard file
-     * will not confuse the external importer, assuming there may be some importer
-     * which presume that there's only one property toward each of  "N", "FN", etc.
-     * Note that more than one "N", "FN", etc. properties are acceptable in vCard spec.
-     */
-    private void testStructuredNameUsePrimaryCommon(int vcardType) {
-        final boolean isV30 = (vcardType == V30);
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
-                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
-                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
-                .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
-                .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
-
-        // With "IS_PRIMARY=1". This is what we should use.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
-                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
-                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
-                .put(StructuredName.PREFIX, "AppropriatePrefix")
-                .put(StructuredName.SUFFIX, "AppropriateSuffix")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle")
-                .put(StructuredName.IS_PRIMARY, 1);
-
-        // With "IS_PRIMARY=1", but we should ignore this time, since this is second, not first.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
-                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
-                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
-                .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
-                .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2")
-                .put(StructuredName.IS_PRIMARY, 1);
-
-        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("N",
-                        "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
-                        + "AppropriatePrefix;AppropriateSuffix",
-                        Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
-                                "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
-                .addExpectedNodeWithOrder("FN",
-                        "AppropriatePrefix AppropriateGivenName "
-                        + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
-                .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
-                .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
-                .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
-
-        if (isV30) {
-            elem.addExpectedNode("SORT-STRING",
-                    "AppropriatePhoneticGiven AppropriatePhoneticMiddle "
-                    + "AppropriatePhoneticFamily");
-        }
-    }
-
-    public void testStructuredNameUsePrimaryV21() {
-        testStructuredNameUsePrimaryCommon(V21);
-    }
-
-    public void testStructuredNameUsePrimaryV30() {
-        testStructuredNameUsePrimaryCommon(V30);
-    }
-
-    /**
-     * Tests that only "super primary" StructuredName is emitted.
-     * See also the comment in {@link #testStructuredNameUsePrimaryCommon(int)}.
-     */
-    private void testStructuredNameUseSuperPrimaryCommon(int vcardType) {
-        final boolean isV30 = (vcardType == V30);
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
-                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
-                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
-                .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
-                .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
-
-        // With "IS_PRIMARY=1", but we should ignore this time.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
-                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
-                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
-                .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
-                .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2")
-                .put(StructuredName.IS_PRIMARY, 1);
-
-        // With "IS_SUPER_PRIMARY=1". This is what we should use.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
-                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
-                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
-                .put(StructuredName.PREFIX, "AppropriatePrefix")
-                .put(StructuredName.SUFFIX, "AppropriateSuffix")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle")
-                .put(StructuredName.IS_SUPER_PRIMARY, 1);
-
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName3")
-                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName3")
-                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName3")
-                .put(StructuredName.PREFIX, "DoNotEmitPrefix3")
-                .put(StructuredName.SUFFIX, "DoNotEmitSuffix3")
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily3")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven3")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle3")
-                .put(StructuredName.IS_PRIMARY, 1);
-
-        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("N",
-                        "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
-                        + "AppropriatePrefix;AppropriateSuffix",
-                        Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
-                                "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
-                .addExpectedNodeWithOrder("FN",
-                        "AppropriatePrefix AppropriateGivenName "
-                        + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
-                .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
-                .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
-                .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
-
-        if (isV30) {
-            elem.addExpectedNode("SORT-STRING",
-                    "AppropriatePhoneticGiven AppropriatePhoneticMiddle"
-                    + " AppropriatePhoneticFamily");
-        }
-    }
-
-    public void testStructuredNameUseSuperPrimaryV21() {
-        testStructuredNameUseSuperPrimaryCommon(V21);
-    }
-
-    public void testStructuredNameUseSuperPrimaryV30() {
-        testStructuredNameUseSuperPrimaryCommon(V30);
-    }
-
-    public void testNickNameV30() {
-        mVerifier.initForExportTest(V30);
-        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
-                .put(Nickname.NAME, "Nicky");
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-            .addExpectedNodeWithOrder("NICKNAME", "Nicky");
-    }
-
-    private void testPhoneBasicCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "1")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "1", new TypeSet("HOME"));
-    }
-
-    public void testPhoneBasicV21() {
-        testPhoneBasicCommon(V21);
-    }
-
-    public void testPhoneBasicV30() {
-        testPhoneBasicCommon(V30);
-    }
-
-    public void testPhoneRefrainFormatting() {
-        mVerifier.initForExportTest(V21 | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING);
-        mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "1234567890(abcdefghijklmnopqrstuvwxyz)")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "1234567890(abcdefghijklmnopqrstuvwxyz)",
-                        new TypeSet("HOME"));
-    }
-
-    /**
-     * Tests that vCard composer emits corresponding type param which we expect.
-     */
-    private void testPhoneVariousTypeSupport(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "10")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "20")
-                .put(Phone.TYPE, Phone.TYPE_WORK);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "30")
-                .put(Phone.TYPE, Phone.TYPE_FAX_HOME);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "40")
-                .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "50")
-                .put(Phone.TYPE, Phone.TYPE_MOBILE);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "60")
-                .put(Phone.TYPE, Phone.TYPE_PAGER);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "70")
-                .put(Phone.TYPE, Phone.TYPE_OTHER);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "80")
-                .put(Phone.TYPE, Phone.TYPE_CAR);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "90")
-                .put(Phone.TYPE, Phone.TYPE_COMPANY_MAIN);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "100")
-                .put(Phone.TYPE, Phone.TYPE_ISDN);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "110")
-                .put(Phone.TYPE, Phone.TYPE_MAIN);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "120")
-                .put(Phone.TYPE, Phone.TYPE_OTHER_FAX);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "130")
-                .put(Phone.TYPE, Phone.TYPE_TELEX);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "140")
-                .put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "150")
-                .put(Phone.TYPE, Phone.TYPE_WORK_PAGER);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "160")
-                .put(Phone.TYPE, Phone.TYPE_MMS);
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "10", new TypeSet("HOME"))
-                .addExpectedNode("TEL", "20", new TypeSet("WORK"))
-                .addExpectedNode("TEL", "30", new TypeSet("HOME", "FAX"))
-                .addExpectedNode("TEL", "40", new TypeSet("WORK", "FAX"))
-                .addExpectedNode("TEL", "50", new TypeSet("CELL"))
-                .addExpectedNode("TEL", "60", new TypeSet("PAGER"))
-                .addExpectedNode("TEL", "70", new TypeSet("VOICE"))
-                .addExpectedNode("TEL", "80", new TypeSet("CAR"))
-                .addExpectedNode("TEL", "90", new TypeSet("WORK", "PREF"))
-                .addExpectedNode("TEL", "100", new TypeSet("ISDN"))
-                .addExpectedNode("TEL", "110", new TypeSet("PREF"))
-                .addExpectedNode("TEL", "120", new TypeSet("FAX"))
-                .addExpectedNode("TEL", "130", new TypeSet("TLX"))
-                .addExpectedNode("TEL", "140", new TypeSet("WORK", "CELL"))
-                .addExpectedNode("TEL", "150", new TypeSet("WORK", "PAGER"))
-                .addExpectedNode("TEL", "160", new TypeSet("MSG"));
-    }
-
-    public void testPhoneVariousTypeSupportV21() {
-        testPhoneVariousTypeSupport(V21);
-    }
-
-    public void testPhoneVariousTypeSupportV30() {
-        testPhoneVariousTypeSupport(V30);
-    }
-
-    /**
-     * Tests that "PREF"s are emitted appropriately.
-     */
-    private void testPhonePrefHandlingCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "1")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "2")
-                .put(Phone.TYPE, Phone.TYPE_WORK)
-                .put(Phone.IS_PRIMARY, 1);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "3")
-                .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
-                .put(Phone.IS_PRIMARY, 1);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "4")
-                .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "4", new TypeSet("WORK", "FAX"))
-                .addExpectedNode("TEL", "3", new TypeSet("HOME", "FAX", "PREF"))
-                .addExpectedNode("TEL", "2", new TypeSet("WORK", "PREF"))
-                .addExpectedNode("TEL", "1", new TypeSet("HOME"));
-    }
-
-    public void testPhonePrefHandlingV21() {
-        testPhonePrefHandlingCommon(V21);
-    }
-
-    public void testPhonePrefHandlingV30() {
-        testPhonePrefHandlingCommon(V30);
-    }
-
-    private void testMiscPhoneTypeHandling(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "1")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "Modem");
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "2")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "MSG");
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "3")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "BBS");
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "4")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "VIDEO");
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "5")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "6")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "_AUTO_CELL");  // The old indicator for the type mobile.
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "7")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "\u643A\u5E2F");  // Mobile phone in Japanese Kanji
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "8")
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "invalid");
-        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
-        elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
-                .addExpectedNode("TEL", "2", new TypeSet("MSG"))
-                .addExpectedNode("TEL", "3", new TypeSet("BBS"))
-                .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
-                .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
-                .addExpectedNode("TEL", "6", new TypeSet("CELL"))
-                .addExpectedNode("TEL", "7", new TypeSet("CELL"))
-                .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
-    }
-
-    public void testPhoneTypeHandlingV21() {
-        testMiscPhoneTypeHandling(V21);
-    }
-
-    public void testPhoneTypeHandlingV30() {
-        testMiscPhoneTypeHandling(V30);
-    }
-
-    private void testEmailBasicCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "sample@example.com");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-            .addExpectedNode("EMAIL", "sample@example.com");
-    }
-
-    public void testEmailBasicV21() {
-        testEmailBasicCommon(V21);
-    }
-
-    public void testEmailBasicV30() {
-        testEmailBasicCommon(V30);
-    }
-
-    private void testEmailVariousTypeSupportCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "type_home@example.com")
-                .put(Email.TYPE, Email.TYPE_HOME);
-        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "type_work@example.com")
-                .put(Email.TYPE, Email.TYPE_WORK);
-        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "type_mobile@example.com")
-                .put(Email.TYPE, Email.TYPE_MOBILE);
-        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "type_other@example.com")
-                .put(Email.TYPE, Email.TYPE_OTHER);
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "type_work@example.com", new TypeSet("WORK"))
-                .addExpectedNode("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
-                .addExpectedNode("EMAIL", "type_other@example.com");
-    }
-
-    public void testEmailVariousTypeSupportV21() {
-        testEmailVariousTypeSupportCommon(V21);
-    }
-
-    public void testEmailVariousTypeSupportV30() {
-        testEmailVariousTypeSupportCommon(V30);
-    }
-
-    private void testEmailPrefHandlingCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "type_home@example.com")
-                .put(Email.TYPE, Email.TYPE_HOME)
-                .put(Email.IS_PRIMARY, 1);
-        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "type_notype@example.com")
-                .put(Email.IS_PRIMARY, 1);
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
-                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
-    }
-
-    public void testEmailPrefHandlingV21() {
-        testEmailPrefHandlingCommon(V21);
-    }
-
-    public void testEmailPrefHandlingV30() {
-        testEmailPrefHandlingCommon(V30);
-    }
-
-    private void testPostalAddressCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POBOX, "Pobox")
-                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood")
-                .put(StructuredPostal.STREET, "Street")
-                .put(StructuredPostal.CITY, "City")
-                .put(StructuredPostal.REGION, "Region")
-                .put(StructuredPostal.POSTCODE, "100")
-                .put(StructuredPostal.COUNTRY, "Country")
-                .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted Address")
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK);
-        // adr-value    = 0*6(text-value ";") text-value
-        //              ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
-        //              ; Country Name
-        //
-        // The NEIGHBORHOOD field is appended after the CITY field.
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("ADR",
-                        Arrays.asList("Pobox", "", "Street", "City Neighborhood",
-                                "Region", "100", "Country"), new TypeSet("WORK"));
-    }
-
-    public void testPostalAddressV21() {
-        testPostalAddressCommon(V21);
-    }
-
-    public void testPostalAddressV30() {
-        testPostalAddressCommon(V30);
-    }
-
-    private void testPostalAddressNonNeighborhood(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.CITY, "City");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("ADR",
-                        Arrays.asList("", "", "", "City", "", "", ""), new TypeSet("HOME"));
-    }
-
-    public void testPostalAddressNonNeighborhoodV21() {
-        testPostalAddressNonNeighborhood(V21);
-    }
-
-    public void testPostalAddressNonNeighborhoodV30() {
-        testPostalAddressNonNeighborhood(V30);
-    }
-
-    private void testPostalAddressNonCity(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("ADR",
-                        Arrays.asList("", "", "", "Neighborhood", "", "", ""), new TypeSet("HOME"));
-    }
-
-    public void testPostalAddressNonCityV21() {
-        testPostalAddressNonCity(V21);
-    }
-
-    public void testPostalAddressNonCityV30() {
-        testPostalAddressNonCity(V30);
-    }
-
-    private void testPostalOnlyWithFormattedAddressCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.REGION, "")  // Must be ignored.
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                "Formatted address CA 123-334 United Statue");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
-                        Arrays.asList("", "Formatted address CA 123-334 United Statue",
-                                "", "", "", "", ""), new TypeSet("HOME"));
-    }
-
-    public void testPostalOnlyWithFormattedAddressV21() {
-        testPostalOnlyWithFormattedAddressCommon(V21);
-    }
-
-    public void testPostalOnlyWithFormattedAddressV30() {
-        testPostalOnlyWithFormattedAddressCommon(V30);
-    }
-
-    /**
-     * Tests that the vCard composer honors formatted data when it is available
-     * even when it is partial.
-     */
-    private void testPostalWithBothStructuredAndFormattedCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POBOX, "Pobox")
-                .put(StructuredPostal.COUNTRY, "Country")
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                        "Formatted address CA 123-334 United Statue");  // Should be ignored
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("ADR", "Pobox;;;;;;Country",
-                        Arrays.asList("Pobox", "", "", "", "", "", "Country"),
-                        new TypeSet("HOME"));
-    }
-
-    public void testPostalWithBothStructuredAndFormattedV21() {
-        testPostalWithBothStructuredAndFormattedCommon(V21);
-    }
-
-    public void testPostalWithBothStructuredAndFormattedV30() {
-        testPostalWithBothStructuredAndFormattedCommon(V30);
-    }
-
-    private void testOrganizationCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "CompanyX")
-                .put(Organization.DEPARTMENT, "DepartmentY")
-                .put(Organization.TITLE, "TitleZ")
-                .put(Organization.JOB_DESCRIPTION, "Description Rambda")  // Ignored.
-                .put(Organization.OFFICE_LOCATION, "Mountain View")  // Ignored.
-                .put(Organization.PHONETIC_NAME, "PhoneticName!")  // Ignored
-                .put(Organization.SYMBOL, "(^o^)/~~");  // Ignore him (her).
-        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
-                .putNull(Organization.COMPANY)
-                .put(Organization.DEPARTMENT, "DepartmentXX")
-                .putNull(Organization.TITLE);
-        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "CompanyXYZ")
-                .putNull(Organization.DEPARTMENT)
-                .put(Organization.TITLE, "TitleXYZYX");
-        // Currently we do not use group but depend on the order.
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNodeWithOrder("ORG", "CompanyX;DepartmentY",
-                        Arrays.asList("CompanyX", "DepartmentY"))
-                .addExpectedNodeWithOrder("TITLE", "TitleZ")
-                .addExpectedNodeWithOrder("ORG", "DepartmentXX")
-                .addExpectedNodeWithOrder("ORG", "CompanyXYZ")
-                .addExpectedNodeWithOrder("TITLE", "TitleXYZYX");
-    }
-
-    public void testOrganizationV21() {
-        testOrganizationCommon(V21);
-    }
-
-    public void testOrganizationV30() {
-        testOrganizationCommon(V30);
-    }
-
-    private void testImVariousTypeSupportCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
-                .put(Im.DATA, "aim");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_MSN)
-                .put(Im.DATA, "msn");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_YAHOO)
-                .put(Im.DATA, "yahoo");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_SKYPE)
-                .put(Im.DATA, "skype");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_QQ)
-                .put(Im.DATA, "qq");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK)
-                .put(Im.DATA, "google talk");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_ICQ)
-                .put(Im.DATA, "icq");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_JABBER)
-                .put(Im.DATA, "jabber");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING)
-                .put(Im.DATA, "netmeeting");
-
-        // No determined way to express unknown type...
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("X-JABBER", "jabber")
-                .addExpectedNode("X-ICQ", "icq")
-                .addExpectedNode("X-GOOGLE-TALK", "google talk")
-                .addExpectedNode("X-QQ", "qq")
-                .addExpectedNode("X-SKYPE-USERNAME", "skype")
-                .addExpectedNode("X-YAHOO", "yahoo")
-                .addExpectedNode("X-MSN", "msn")
-                .addExpectedNode("X-NETMEETING", "netmeeting")
-                .addExpectedNode("X-AIM", "aim");
-    }
-
-    public void testImBasiV21() {
-        testImVariousTypeSupportCommon(V21);
-    }
-
-    public void testImBasicV30() {
-        testImVariousTypeSupportCommon(V30);
-    }
-
-    private void testImPrefHandlingCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
-                .put(Im.DATA, "aim1");
-        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
-                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
-                .put(Im.DATA, "aim2")
-                .put(Im.TYPE, Im.TYPE_HOME)
-                .put(Im.IS_PRIMARY, 1);
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("X-AIM", "aim1")
-                .addExpectedNode("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
-    }
-
-    public void testImPrefHandlingV21() {
-        testImPrefHandlingCommon(V21);
-    }
-
-    public void testImPrefHandlingV30() {
-        testImPrefHandlingCommon(V30);
-    }
-
-    private void testWebsiteCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
-                .put(Website.URL, "http://website.example.android.com/index.html")
-                .put(Website.TYPE, Website.TYPE_BLOG);
-        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
-                .put(Website.URL, "ftp://ftp.example.android.com/index.html")
-                .put(Website.TYPE, Website.TYPE_FTP);
-
-        // We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("URL", "ftp://ftp.example.android.com/index.html")
-                .addExpectedNode("URL", "http://website.example.android.com/index.html");
-    }
-
-    public void testWebsiteV21() {
-        testWebsiteCommon(V21);
-    }
-
-    public void testWebsiteV30() {
-        testWebsiteCommon(V30);
-    }
-
-    private String getAndroidPropValue(final String mimeType, String value, Integer type) {
-        return getAndroidPropValue(mimeType, value, type, null);
-    }
-
-    private String getAndroidPropValue(final String mimeType, String value,
-            Integer type, String label) {
-        return (mimeType + ";" + value + ";"
-                + (type != null ? type : "") + ";"
-                + (label != null ? label : "") + ";;;;;;;;;;;;");
-    }
-
-    private void testEventCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
-                .put(Event.TYPE, Event.TYPE_ANNIVERSARY)
-                .put(Event.START_DATE, "1982-06-16");
-        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
-                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
-                .put(Event.START_DATE, "2008-10-22");
-        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
-                .put(Event.TYPE, Event.TYPE_OTHER)
-                .put(Event.START_DATE, "2018-03-12");
-        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
-                .put(Event.TYPE, Event.TYPE_CUSTOM)
-                .put(Event.LABEL, "The last day")
-                .put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
-        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
-                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
-                .put(Event.START_DATE, "2009-05-19");  // Should be ignored.
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("BDAY", "2008-10-22")
-                .addExpectedNode("X-ANDROID-CUSTOM",
-                        getAndroidPropValue(
-                                Event.CONTENT_ITEM_TYPE, "1982-06-16", Event.TYPE_ANNIVERSARY))
-                .addExpectedNode("X-ANDROID-CUSTOM",
-                        getAndroidPropValue(
-                                Event.CONTENT_ITEM_TYPE, "2018-03-12", Event.TYPE_OTHER))
-                .addExpectedNode("X-ANDROID-CUSTOM",
-                        getAndroidPropValue(
-                                Event.CONTENT_ITEM_TYPE,
-                                "When the Tower of Hanoi with 64 rings is completed.",
-                                Event.TYPE_CUSTOM, "The last day"));
-    }
-
-    public void testEventV21() {
-        testEventCommon(V21);
-    }
-
-    public void testEventV30() {
-        testEventCommon(V30);
-    }
-
-    private void testNoteCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "note1");
-        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "note2")
-                .put(Note.IS_PRIMARY, 1);  // Just ignored.
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNodeWithOrder("NOTE", "note1")
-                .addExpectedNodeWithOrder("NOTE", "note2");
-    }
-
-    public void testNoteV21() {
-        testNoteCommon(V21);
-    }
-
-    public void testNoteV30() {
-        testNoteCommon(V30);
-    }
-
-    private void testPhotoCommon(int vcardType) {
-        final boolean isV30 = vcardType == V30;
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "PhotoTest");
-        entry.addContentValues(Photo.CONTENT_ITEM_TYPE)
-                .put(Photo.PHOTO, sPhotoByteArray);
-
-        ContentValues contentValuesForPhoto = new ContentValues();
-        contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("FN", "PhotoTest")
-                .addExpectedNode("N", "PhotoTest;;;;",
-                        Arrays.asList("PhotoTest", "", "", "", ""))
-                .addExpectedNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
-                        contentValuesForPhoto, new TypeSet("JPEG"), null);
-    }
-
-    public void testPhotoV21() {
-        testPhotoCommon(V21);
-    }
-
-    public void testPhotoV30() {
-        testPhotoCommon(V30);
-    }
-
-    private void testRelationCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        mVerifier.addInputEntry().addContentValues(Relation.CONTENT_ITEM_TYPE)
-                .put(Relation.TYPE, Relation.TYPE_MOTHER)
-                .put(Relation.NAME, "Ms. Mother");
-        mVerifier.addContentValuesVerifierElem().addExpected(Relation.CONTENT_ITEM_TYPE)
-                .put(Relation.TYPE, Relation.TYPE_MOTHER)
-                .put(Relation.NAME, "Ms. Mother");
-    }
-
-    public void testRelationV21() {
-        testRelationCommon(V21);
-    }
-
-    public void testRelationV30() {
-        testRelationCommon(V30);
-    }
-
-    public void testV30HandleEscape() {
-        mVerifier.initForExportTest(V30);
-        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\\")
-                .put(StructuredName.GIVEN_NAME, ";")
-                .put(StructuredName.MIDDLE_NAME, ",")
-                .put(StructuredName.PREFIX, "\n")
-                .put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
-        // Verifies the vCard String correctly escapes each character which must be escaped.
-        mVerifier.addLineVerifierElem()
-                .addExpected("N:\\\\;\\;;\\,;\\n;")
-                .addExpected("FN:[<{Unescaped:Asciis}>]");
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("FN", "[<{Unescaped:Asciis}>]")
-                .addExpectedNode("N", Arrays.asList("\\", ";", ",", "\n", ""));
-    }
-
-    /**
-     * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
-     * We use Android-specific "X-ANDROID-CUSTOM" property.
-     * This test verifies the functionality.
-     */
-    public void testNickNameV21() {
-        mVerifier.initForExportTest(V21);
-        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
-                .put(Nickname.NAME, "Nicky");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("X-ANDROID-CUSTOM",
-                        Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
-        mVerifier.addContentValuesVerifierElem().addExpected(Nickname.CONTENT_ITEM_TYPE)
-                .put(Nickname.NAME, "Nicky");
-    }
-
-    public void testTolerateBrokenPhoneNumberEntryV21() {
-        mVerifier.initForExportTest(V21);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_HOME)
-                .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo);"
-                        + "777-888-9999 (Chicago);111-222-3333 (Miami)");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "111-222-3333", new TypeSet("HOME"))
-                .addExpectedNode("TEL", "444-555-5666", new TypeSet("HOME"))
-                .addExpectedNode("TEL", "777-888-9999", new TypeSet("HOME"));
-    }
-
-    private void testPickUpNonEmptyContentValuesCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.IS_PRIMARY, 1);  // Empty name. Should be ignored.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "family1");  // Not primary. Should be ignored.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.IS_PRIMARY, 1)
-                .put(StructuredName.FAMILY_NAME, "family2");  // This entry is what we want.
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.IS_PRIMARY, 1)
-                .put(StructuredName.FAMILY_NAME, "family3");
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "family4");
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("N", Arrays.asList("family2", "", "", "", ""))
-                .addExpectedNode("FN", "family2");
-    }
-
-    public void testPickUpNonEmptyContentValuesV21() {
-        testPickUpNonEmptyContentValuesCommon(V21);
-    }
-
-    public void testPickUpNonEmptyContentValuesV30() {
-        testPickUpNonEmptyContentValuesCommon(V30);
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/VCardImporterTests.java b/vcard/tests/src/com/android/vcard/tests/VCardImporterTests.java
deleted file mode 100644
index 045c0d9..0000000
--- a/vcard/tests/src/com/android/vcard/tests/VCardImporterTests.java
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.tests.test_utils.ContentValuesVerifier;
-import com.android.vcard.tests.test_utils.ContentValuesVerifierElem;
-import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem.TypeSet;
-
-import java.util.Arrays;
-
-public class VCardImporterTests extends VCardTestsBase {
-    // Push data into int array at first since values like 0x80 are
-    // interpreted as int by the compiler and casting all of them is
-    // cumbersome...
-    private static final int[] sPhotoIntArrayForComplicatedCase = {
-        0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
-        0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
-        0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
-        0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
-        0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
-        0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
-        0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
-        0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
-        0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
-        0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
-        0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
-        0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
-        0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
-        0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
-        0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
-        0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
-        0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
-        0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
-        0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
-        0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
-        0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
-        0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
-        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-        0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
-        0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
-        0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
-        0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
-        0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
-        0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
-        0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
-        0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
-        0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
-        0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
-        0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
-        0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
-        0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
-        0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
-        0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
-        0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
-        0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
-        0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
-        0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
-        0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
-        0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
-        0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
-        0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
-        0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-        0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
-        0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
-        0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
-        0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
-        0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
-        0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
-        0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
-        0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
-        0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
-        0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
-        0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
-        0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
-        0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
-        0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
-        0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
-        0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-        0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-        0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
-        0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
-        0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
-        0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
-        0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
-        0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
-        0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
-        0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
-        0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
-        0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
-        0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
-        0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
-        0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
-        0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
-        0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
-        0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
-        0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
-        0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-        0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
-        0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
-        0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
-        0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
-        0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
-        0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
-        0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
-        0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
-        0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
-        0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
-        0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
-        0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
-        0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
-        0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
-        0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
-        0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
-        0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
-        0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
-        0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
-        0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
-        0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
-        0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
-        0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
-        0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
-        0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
-        0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
-        0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
-        0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
-        0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
-        0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-        0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
-        0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
-        0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
-        0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
-        0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
-        0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
-        0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
-        0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
-        0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
-        0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
-        0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
-        0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
-        0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
-        0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-        0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
-        0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
-        0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
-        0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
-        0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
-        0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
-        0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
-        0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
-        0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
-        0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
-        0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
-        0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
-        0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
-        0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
-        0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
-        0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
-        0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
-        0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
-        0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
-        0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
-        0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
-        0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
-        0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
-        0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
-        0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
-        0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
-        0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
-        0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
-        0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
-        0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
-        0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
-        0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
-        0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
-        0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
-        0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
-        0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
-        0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
-        0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
-        0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
-        0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
-        0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
-        0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
-        0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
-        0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
-        0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
-        0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
-        0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
-        0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
-        0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
-        0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
-        0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
-        0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
-        0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
-        0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
-        0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
-        0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
-        0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
-        0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
-        0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
-        0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
-        0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
-        0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
-        0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
-        0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
-        0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
-        0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
-        0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
-        0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
-        0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
-        0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
-        0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
-        0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
-        0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
-        0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
-        0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
-        0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
-        0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
-        0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
-        0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
-        0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
-        0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
-        0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
-        0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
-        0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
-        0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
-        0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
-        0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
-        0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
-        0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
-        0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
-        0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
-        0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
-        0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
-        0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
-        0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-        0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
-        0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
-        0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
-        0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
-        0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
-        0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
-        0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
-        0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
-        0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
-        0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
-        0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
-        0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
-        0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
-        0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
-        0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
-        0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
-        0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
-        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-        0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
-        0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
-        0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
-        0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
-        0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
-        0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
-        0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
-        0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
-        0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
-        0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
-        0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
-        0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
-        0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-        0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
-        0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
-        0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
-        0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
-        0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
-        0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
-        0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
-        0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
-        0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
-        0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
-        0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
-        0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
-        0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
-        0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
-        0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
-        0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
-        0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
-        0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
-        0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
-        0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
-        0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
-        0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
-        0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
-        0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
-        0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
-        0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
-        0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
-        0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
-        0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
-        0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
-        0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
-        0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
-        0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
-        0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
-        0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
-        0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
-        0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
-        0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
-        0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
-        0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
-        0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
-        0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
-        0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
-        0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
-        0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
-        0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
-        0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
-        0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
-        0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
-        0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
-        0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
-        0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
-        0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
-        0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
-        0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
-        0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
-        0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
-        0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
-        0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
-        0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
-        0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
-        0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
-        0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
-        0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
-        0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
-        0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
-        0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
-        0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
-        0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
-        0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
-        0x0c, 0xd1, 0x00, 0xff, 0xd9};
-
-    /* package */ static final byte[] sPhotoByteArrayForComplicatedCase;
-
-    static {
-        final int length = sPhotoIntArrayForComplicatedCase.length;
-        sPhotoByteArrayForComplicatedCase = new byte[length];
-        for (int i = 0; i < length; i++) {
-            sPhotoByteArrayForComplicatedCase[i] = (byte)sPhotoIntArrayForComplicatedCase[i];
-        }
-    }
-
-    public void testV21SimpleCase1_Parsing() {
-        mVerifier.initForImportTest(V21, R.raw.v21_simple_1);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""));
-    }
-
-    public void testV21SimpleCase1_Type_Generic() {
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_GENERIC, R.raw.v21_simple_1);
-        mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                        .put(StructuredName.FAMILY_NAME, "Ando")
-                        .put(StructuredName.GIVEN_NAME, "Roid")
-                        .put(StructuredName.DISPLAY_NAME, "Roid Ando");
-    }
-
-    public void testV21SimpleCase1_Type_Japanese() {
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_simple_1);
-        mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                        .put(StructuredName.FAMILY_NAME, "Ando")
-                        .put(StructuredName.GIVEN_NAME, "Roid")
-                        // If name-related strings only contains printable Ascii,
-                        // the order is remained to be US's:
-                        // "Prefix Given Middle Family Suffix"
-                        .put(StructuredName.DISPLAY_NAME, "Roid Ando");
-    }
-
-    public void testV21SimpleCase2() {
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_simple_2);
-        mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                        .put(StructuredName.DISPLAY_NAME, "Ando Roid");
-    }
-
-    public void testV21SimpleCase3() {
-        mVerifier.initForImportTest(V21, R.raw.v21_simple_3);
-        mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                        .put(StructuredName.FAMILY_NAME, "Ando")
-                        .put(StructuredName.GIVEN_NAME, "Roid")
-                        // "FN" field should be prefered since it should contain the original
-                        // order intended by the author of the file.
-                        .put(StructuredName.DISPLAY_NAME, "Ando Roid");
-    }
-
-    /**
-     * Tests ';' is properly handled by VCardParser implementation.
-     */
-    public void testV21BackslashCase_Parsing() {
-        mVerifier.initForImportTest(V21, R.raw.v21_backslash);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;",
-                        Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
-                .addExpectedNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
-        
-    }
-
-    /**
-     * Tests ContactStruct correctly ignores redundant fields in "N" property values and
-     * inserts name related data.
-     */
-    public void testV21BackslashCase() {
-        mVerifier.initForImportTest(V21, R.raw.v21_backslash);
-        mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                        // FAMILY_NAME is empty and removed in this test...
-                        .put(StructuredName.GIVEN_NAME, "A;B\\")
-                        .put(StructuredName.MIDDLE_NAME, "C\\;")
-                        .put(StructuredName.PREFIX, "D")
-                        .put(StructuredName.SUFFIX, ":E")
-                        .put(StructuredName.DISPLAY_NAME, "A;B\\C\\;D:E\\\\");
-    }
-
-    public void testOrgBeforTitle() {
-        mVerifier.initForImportTest(V21, R.raw.v21_org_before_title);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.DISPLAY_NAME, "Normal Guy");
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "Company")
-                .put(Organization.DEPARTMENT, "Organization Devision Room Sheet No.")
-                .put(Organization.TITLE, "Excellent Janitor")
-                .put(Organization.TYPE, Organization.TYPE_WORK);
-    }
-
-    public void testTitleBeforOrg() {
-        mVerifier.initForImportTest(V21, R.raw.v21_title_before_org);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.DISPLAY_NAME, "Nice Guy");
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "Marverous")
-                .put(Organization.DEPARTMENT, "Perfect Great Good Bad Poor")
-                .put(Organization.TITLE, "Cool Title")
-                .put(Organization.TYPE, Organization.TYPE_WORK);
-    }
-
-    /**
-     * Verifies that vCard importer correctly interpret "PREF" attribute to IS_PRIMARY.
-     * The data contain three cases: one "PREF", no "PREF" and multiple "PREF", in each type.
-     */
-    public void testV21PrefToIsPrimary() {
-        mVerifier.initForImportTest(V21, R.raw.v21_pref_handling);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.DISPLAY_NAME, "Smith");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "1")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "2")
-                .put(Phone.TYPE, Phone.TYPE_WORK)
-                .put(Phone.IS_PRIMARY, 1);
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "3")
-                .put(Phone.TYPE, Phone.TYPE_ISDN);
-        elem.addExpected(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "test@example.com")
-                .put(Email.TYPE, Email.TYPE_HOME)
-                .put(Email.IS_PRIMARY, 1);
-        elem.addExpected(Email.CONTENT_ITEM_TYPE)
-                .put(Email.DATA, "test2@examination.com")
-                .put(Email.TYPE, Email.TYPE_MOBILE)
-                .put(Email.IS_PRIMARY, 1);
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "Company")
-                .put(Organization.TITLE, "Engineer")
-                .put(Organization.TYPE, Organization.TYPE_WORK);
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "Mystery")
-                .put(Organization.TITLE, "Blogger")
-                .put(Organization.TYPE, Organization.TYPE_WORK);
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "Poetry")
-                .put(Organization.TITLE, "Poet")
-                .put(Organization.TYPE, Organization.TYPE_WORK);
-    }
-
-    /**
-     * Tests all the properties in a complicated vCard are correctly parsed by the VCardParser.
-     */
-    public void testV21ComplicatedCase_Parsing() {
-        mVerifier.initForImportTest(V21, R.raw.v21_complicated);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", "Gump;Forrest;Hoge;Pos;Tao",
-                        Arrays.asList("Gump", "Forrest", "Hoge", "Pos", "Tao"))
-                .addExpectedNodeWithOrder("FN", "Joe Due")
-                .addExpectedNodeWithOrder("ORG", "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
-                        Arrays.asList("Gump Shrimp Co.", "Sales Dept.;Manager", "Fish keeper"))
-                .addExpectedNodeWithOrder("ROLE", "Fish Cake Keeper!")
-                .addExpectedNodeWithOrder("TITLE", "Shrimp Man")
-                .addExpectedNodeWithOrder("X-CLASS", "PUBLIC")
-                .addExpectedNodeWithOrder("TEL", "(111) 555-1212", new TypeSet("WORK", "VOICE"))
-                .addExpectedNodeWithOrder("TEL", "(404) 555-1212", new TypeSet("HOME", "VOICE"))
-                .addExpectedNodeWithOrder("TEL", "0311111111", new TypeSet("CELL"))
-                .addExpectedNodeWithOrder("TEL", "0322222222", new TypeSet("VIDEO"))
-                .addExpectedNodeWithOrder("TEL", "0333333333", new TypeSet("VOICE"))
-                .addExpectedNodeWithOrder("ADR",
-                        ";;100 Waters Edge;Baytown;LA;30314;United States of America",
-                        Arrays.asList("", "", "100 Waters Edge", "Baytown",
-                                "LA", "30314", "United States of America"),
-                                null, null, new TypeSet("WORK"), null)
-                .addExpectedNodeWithOrder("LABEL",
-                        "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited  States of America",
-                        null, null, mContentValuesForQP, new TypeSet("WORK"), null)
-                .addExpectedNodeWithOrder("ADR",
-                        ";;42 Plantation St.;Baytown;LA;30314;United States of America",
-                        Arrays.asList("", "", "42 Plantation St.", "Baytown",
-                                "LA", "30314", "United States of America"), null, null,
-                                new TypeSet("HOME"), null)
-                .addExpectedNodeWithOrder("LABEL",
-                        "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited  States of America",
-                        null, null, mContentValuesForQP,
-                        new TypeSet("HOME"), null)
-                .addExpectedNodeWithOrder("EMAIL", "forrestgump@walladalla.com",
-                        new TypeSet("PREF", "INTERNET"))
-                .addExpectedNodeWithOrder("EMAIL", "cell@example.com", new TypeSet("CELL"))
-                .addExpectedNodeWithOrder("NOTE", "The following note is the example from RFC 2045.")
-                .addExpectedNodeWithOrder("NOTE",
-                        "Now's the time for all folk to come to the aid of their country.",
-                        null, null, mContentValuesForQP, null, null)
-                .addExpectedNodeWithOrder("PHOTO", null,
-                        null, sPhotoByteArrayForComplicatedCase, mContentValuesForBase64V21,
-                        new TypeSet("JPEG"), null)
-                .addExpectedNodeWithOrder("X-ATTRIBUTE", "Some String")
-                .addExpectedNodeWithOrder("BDAY", "19800101")
-                .addExpectedNodeWithOrder("GEO", "35.6563854,139.6994233")
-                .addExpectedNodeWithOrder("URL", "http://www.example.com/")
-                .addExpectedNodeWithOrder("REV", "20080424T195243Z");
-    }
-
-    /**
-     * Checks ContactStruct correctly inserts values in a complicated vCard
-     * into ContentResolver.
-     */
-    public void testV21ComplicatedCase() {
-        mVerifier.initForImportTest(V21, R.raw.v21_complicated);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "Gump")
-                .put(StructuredName.GIVEN_NAME, "Forrest")
-                .put(StructuredName.MIDDLE_NAME, "Hoge")
-                .put(StructuredName.PREFIX, "Pos")
-                .put(StructuredName.SUFFIX, "Tao")
-                .put(StructuredName.DISPLAY_NAME, "Joe Due");
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.TYPE, Organization.TYPE_WORK)
-                .put(Organization.COMPANY, "Gump Shrimp Co.")
-                .put(Organization.DEPARTMENT, "Sales Dept.;Manager Fish keeper")
-                .put(Organization.TITLE, "Shrimp Man");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_WORK)
-                // Phone number is expected to be formated with NAMP format in default.
-                .put(Phone.NUMBER, "111-555-1212");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_HOME)
-                .put(Phone.NUMBER, "404-555-1212");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_MOBILE)
-                .put(Phone.NUMBER, "031-111-1111");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "VIDEO")
-                .put(Phone.NUMBER, "032-222-2222");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "VOICE")
-                .put(Phone.NUMBER, "033-333-3333");
-        elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
-                .put(StructuredPostal.COUNTRY, "United States of America")
-                .put(StructuredPostal.POSTCODE, "30314")
-                .put(StructuredPostal.REGION, "LA")
-                .put(StructuredPostal.CITY, "Baytown")
-                .put(StructuredPostal.STREET, "100 Waters Edge")
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                        "100 Waters Edge Baytown LA 30314 United States of America");
-        elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
-                .put(StructuredPostal.COUNTRY, "United States of America")
-                .put(StructuredPostal.POSTCODE, "30314")
-                .put(StructuredPostal.REGION, "LA")
-                .put(StructuredPostal.CITY, "Baytown")
-                .put(StructuredPostal.STREET, "42 Plantation St.")
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                        "42 Plantation St. Baytown LA 30314 United States of America");
-        elem.addExpected(Email.CONTENT_ITEM_TYPE)
-                // "TYPE=INTERNET" -> TYPE_CUSTOM + the label "INTERNET"
-                .put(Email.TYPE, Email.TYPE_CUSTOM)
-                .put(Email.LABEL, "INTERNET")
-                .put(Email.DATA, "forrestgump@walladalla.com")
-                .put(Email.IS_PRIMARY, 1);
-        elem.addExpected(Email.CONTENT_ITEM_TYPE)
-                .put(Email.TYPE, Email.TYPE_MOBILE)
-                .put(Email.DATA, "cell@example.com");
-        elem.addExpected(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "The following note is the example from RFC 2045.");
-        elem.addExpected(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE,
-                        "Now's the time for all folk to come to the aid of their country.");
-        elem.addExpected(Photo.CONTENT_ITEM_TYPE)
-                // No information about its image format can be inserted.
-                .put(Photo.PHOTO, sPhotoByteArrayForComplicatedCase);
-        elem.addExpected(Event.CONTENT_ITEM_TYPE)
-                .put(Event.START_DATE, "19800101")
-                .put(Event.TYPE, Event.TYPE_BIRTHDAY);
-        elem.addExpected(Website.CONTENT_ITEM_TYPE)
-                .put(Website.URL, "http://www.example.com/")
-                .put(Website.TYPE, Website.TYPE_HOMEPAGE);
-    }
-
-    public void testV30Simple_Parsing() {
-        mVerifier.initForImportTest(V30, R.raw.v30_simple);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "3.0")
-                .addExpectedNodeWithOrder("FN", "And Roid")
-                .addExpectedNodeWithOrder("N", "And;Roid;;;", Arrays.asList("And", "Roid", "", "", ""))
-                .addExpectedNodeWithOrder("ORG", "Open;Handset; Alliance",
-                        Arrays.asList("Open", "Handset", " Alliance"))
-                .addExpectedNodeWithOrder("SORT-STRING", "android")
-                .addExpectedNodeWithOrder("TEL", "0300000000", new TypeSet("PREF", "VOICE"))
-                .addExpectedNodeWithOrder("CLASS", "PUBLIC")
-                .addExpectedNodeWithOrder("X-GNO", "0")
-                .addExpectedNodeWithOrder("X-GN", "group0")
-                .addExpectedNodeWithOrder("X-REDUCTION", "0")
-                .addExpectedNodeWithOrder("REV", "20081031T065854Z");
-    }
-
-    public void testV30Simple() {
-        mVerifier.initForImportTest(V30, R.raw.v30_simple);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "And")
-                .put(StructuredName.GIVEN_NAME, "Roid")
-                .put(StructuredName.DISPLAY_NAME, "And Roid")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "android");
-        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
-                .put(Organization.COMPANY, "Open")
-                .put(Organization.DEPARTMENT, "Handset  Alliance")
-                .put(Organization.TYPE, Organization.TYPE_WORK);
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "VOICE")
-                .put(Phone.NUMBER, "030-000-0000")
-                .put(Phone.IS_PRIMARY, 1);
-    }
-
-    public void testV21Japanese1_Parsing() {
-        // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
-        // vCard 2.1/3.0 specification does not allow multiple values.
-        // Do not need to handle it as multiple values.
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_japanese_1);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1", null, null, null, null, null)
-                .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
-                        Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
-                        null, mContentValuesForSJis, null, null)
-                .addExpectedNodeWithOrder("SOUND",
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
-                        null, null, mContentValuesForSJis,
-                        new TypeSet("X-IRMC-N"), null)
-                .addExpectedNodeWithOrder("TEL", "0300000000", null, null, null,
-                        new TypeSet("VOICE", "PREF"), null);
-    }
-
-    private void testV21Japanese1Common(int resId, int vcardType, boolean japanese) {
-        mVerifier.initForImportTest(vcardType, resId);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9")
-                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9")
-                // While vCard parser does not split "SOUND" property values,
-                // ContactStruct care it.
-                .put(StructuredName.PHONETIC_GIVEN_NAME,
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                // Phone number formatting is different.
-                .put(Phone.NUMBER, (japanese ? "03-0000-0000" : "030-000-0000"))
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "VOICE")
-                .put(Phone.IS_PRIMARY, 1);
-    }
-
-    /**
-     * Verifies vCard with Japanese can be parsed correctly with
-     * {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_GENERIC}.
-     */
-    public void testV21Japanese1_Type_Generic_Utf8() {
-        testV21Japanese1Common(
-                R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_GENERIC, false);
-    }
-
-    /**
-     * Verifies vCard with Japanese can be parsed correctly with
-     * {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_JAPANESE}.
-     */
-    public void testV21Japanese1_Type_Japanese_Sjis() {
-        testV21Japanese1Common(
-                R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE, true);
-    }
-
-    /**
-     * Verifies vCard with Japanese can be parsed correctly with
-     * {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_JAPANESE}.
-     * since vCard 2.1 specifies the charset of each line if it contains non-Ascii.
-     */
-    public void testV21Japanese1_Type_Japanese_Utf8() {
-        testV21Japanese1Common(
-                R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE, true);
-    }
-
-    public void testV21Japanese2_Parsing() {
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_japanese_2);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
-                        Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
-                                "", "", ""),
-                        null, mContentValuesForSJis, null, null)
-                .addExpectedNodeWithOrder("FN", "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
-                        null, null, mContentValuesForSJis, null, null)
-                .addExpectedNodeWithOrder("SOUND",
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73;\uFF9B\uFF72\uFF84\uFF9E\u0031;;;",
-                        null, null, mContentValuesForSJis,
-                        new TypeSet("X-IRMC-N"), null)
-                .addExpectedNodeWithOrder("ADR",
-                        ";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
-                        "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
-                        "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
-                        "\u968E;;;;150-8512;",
-                        Arrays.asList("",
-                                "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
-                                "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
-                                "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
-                                "\u0036\u968E", "", "", "", "150-8512", ""),
-                        null, mContentValuesForQPAndSJis, new TypeSet("HOME"), null)
-                .addExpectedNodeWithOrder("NOTE", "\u30E1\u30E2", null, null,
-                        mContentValuesForQPAndSJis, null, null);
-    }
-
-    public void testV21Japanese2_Type_Generic_Utf8() {
-        mVerifier.initForImportTest(V21, R.raw.v21_japanese_2);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4")
-                .put(StructuredName.GIVEN_NAME, "\u30ED\u30A4\u30C9\u0031")
-                .put(StructuredName.DISPLAY_NAME,
-                        "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031")
-                // ContactStruct should correctly split "SOUND" property into several elements,
-                // even though VCardParser side does not care it.
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF71\uFF9D\uFF84\uFF9E\uFF73")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF9B\uFF72\uFF84\uFF9E\u0031");
-        elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POSTCODE, "150-8512")
-                .put(StructuredPostal.STREET,
-                        "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
-                        "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
-                        "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
-                        "\u0036\u968E")
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                        "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
-                        "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
-                        "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
-                        "\u0036\u968E 150-8512")
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
-        elem.addExpected(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "\u30E1\u30E2");
-    }
-
-    public void testV21MultipleEntryCase_Parse() {
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_multiple_entry);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
-                        Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
-                        null, mContentValuesForSJis, null, null)
-                .addExpectedNodeWithOrder("SOUND",
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
-                        null, null, mContentValuesForSJis,
-                        new TypeSet("X-IRMC-N"), null)
-                .addExpectedNodeWithOrder("TEL", "9", new TypeSet("X-NEC-SECRET"))
-                .addExpectedNodeWithOrder("TEL", "10", new TypeSet("X-NEC-HOTEL"))
-                .addExpectedNodeWithOrder("TEL", "11", new TypeSet("X-NEC-SCHOOL"))
-                .addExpectedNodeWithOrder("TEL", "12", new TypeSet("FAX", "HOME"));
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
-                        Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
-                        null, mContentValuesForSJis, null, null)
-                .addExpectedNodeWithOrder("SOUND",
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
-                        null, null, mContentValuesForSJis,
-                        new TypeSet("X-IRMC-N"), null)
-                .addExpectedNodeWithOrder("TEL", "13", new TypeSet("MODEM"))
-                .addExpectedNodeWithOrder("TEL", "14", new TypeSet("PAGER"))
-                .addExpectedNodeWithOrder("TEL", "15", new TypeSet("X-NEC-FAMILY"))
-                .addExpectedNodeWithOrder("TEL", "16", new TypeSet("X-NEC-GIRL"));
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
-                        Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
-                        null, mContentValuesForSJis, null, null)
-                .addExpectedNodeWithOrder("SOUND",
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
-                        null, null, mContentValuesForSJis,
-                        new TypeSet("X-IRMC-N"), null)
-                .addExpectedNodeWithOrder("TEL", "17", new TypeSet("X-NEC-BOY"))
-                .addExpectedNodeWithOrder("TEL", "18", new TypeSet("X-NEC-FRIEND"))
-                .addExpectedNodeWithOrder("TEL", "19", new TypeSet("X-NEC-PHS"))
-                .addExpectedNodeWithOrder("TEL", "20", new TypeSet("X-NEC-RESTAURANT"));
-    }
-
-    public void testV21MultipleEntryCase() {
-        mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_multiple_entry);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033")
-                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033")
-                .put(StructuredName.PHONETIC_GIVEN_NAME,
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-SECRET")
-                .put(Phone.NUMBER, "9");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-HOTEL")
-                .put(Phone.NUMBER, "10");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-SCHOOL")
-                .put(Phone.NUMBER, "11");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
-                .put(Phone.NUMBER, "12");
-
-        elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034")
-                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034")
-                .put(StructuredName.PHONETIC_GIVEN_NAME,
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "MODEM")
-                .put(Phone.NUMBER, "13");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_PAGER)
-                .put(Phone.NUMBER, "14");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-FAMILY")
-                .put(Phone.NUMBER, "15");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-GIRL")
-                .put(Phone.NUMBER, "16");
-
-        elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035")
-                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035")
-                .put(StructuredName.PHONETIC_GIVEN_NAME,
-                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-BOY")
-                .put(Phone.NUMBER, "17");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-FRIEND")
-                .put(Phone.NUMBER, "18");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-PHS")
-                .put(Phone.NUMBER, "19");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
-                .put(Phone.LABEL, "NEC-RESTAURANT")
-                .put(Phone.NUMBER, "20");
-    }
-
-    public void testIgnoreAgentV21_Parse() {
-        mVerifier.initForImportTest(V21, R.raw.v21_winmo_65);
-        ContentValues contentValuesForValue = new ContentValues();
-        contentValuesForValue.put("VALUE", "DATE");
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
-                .addExpectedNodeWithOrder("N", Arrays.asList("Example", "", "", "", ""))
-                .addExpectedNodeWithOrder("FN", "Example")
-                .addExpectedNodeWithOrder("ANNIVERSARY", "20091010", contentValuesForValue)
-                .addExpectedNodeWithOrder("AGENT", "")
-                .addExpectedNodeWithOrder("X-CLASS", "PUBLIC")
-                .addExpectedNodeWithOrder("X-REDUCTION", "")
-                .addExpectedNodeWithOrder("X-NO", "");
-    }
-
-    public void testIgnoreAgentV21() {
-        mVerifier.initForImportTest(V21, R.raw.v21_winmo_65);
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "Example")
-                .put(StructuredName.DISPLAY_NAME, "Example");
-    }
-
-    public void testTolerateInvalidCommentLikeLineV21() {
-        mVerifier.initForImportTest(V21, R.raw.v21_invalid_comment_line);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.GIVEN_NAME, "Conference Call")
-                .put(StructuredName.DISPLAY_NAME, "Conference Call");
-        elem.addExpected(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "This is an (sharp ->#<- sharp) example. "
-                        + "This message must NOT be ignored.");
-    }
-
-    public void testPagerV30_Parse() {
-        mVerifier.initForImportTest(V30, R.raw.v30_comma_separated);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "3.0")
-                .addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
-                .addExpectedNodeWithOrder("TEL", "6101231234@pagersample.com",
-                        new TypeSet("WORK", "MSG", "PAGER"));
-    }
-
-    public void testPagerV30() {
-        mVerifier.initForImportTest(V30, R.raw.v30_comma_separated);
-        ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
-        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "F")
-                .put(StructuredName.MIDDLE_NAME, "M")
-                .put(StructuredName.GIVEN_NAME, "G")
-                .put(StructuredName.DISPLAY_NAME, "G M F");
-        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.TYPE, Phone.TYPE_PAGER)
-                .put(Phone.NUMBER, "6101231234@pagersample.com");
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/VCardJapanizationTests.java b/vcard/tests/src/com/android/vcard/tests/VCardJapanizationTests.java
deleted file mode 100644
index 0d0b9f1..0000000
--- a/vcard/tests/src/com/android/vcard/tests/VCardJapanizationTests.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.tests.test_utils.ContactEntry;
-import com.android.vcard.tests.test_utils.ContentValuesBuilder;
-import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem;
-import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem.TypeSet;
-
-import java.util.Arrays;
-
-public class VCardJapanizationTests extends VCardTestsBase {
-    private void testNameUtf8Common(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
-                .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
-                .put(StructuredName.MIDDLE_NAME, "B")
-                .put(StructuredName.PREFIX, "Dr.")
-                .put(StructuredName.SUFFIX, "Ph.D");
-        ContentValues contentValues =
-            (VCardConfig.isV30(vcardType) ? null : mContentValuesForQPAndUtf8);
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
-                        contentValues)
-                .addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
-                        Arrays.asList(
-                                "\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
-                                null, contentValues, null, null);
-    }
-
-    public void testNameUtf8V21() {
-        testNameUtf8Common(VCardConfig.VCARD_TYPE_V21_JAPANESE);
-    }
-
-    public void testNameUtf8V30() {
-        testNameUtf8Common(VCardConfig.VCARD_TYPE_V30_JAPANESE);
-    }
-
-    public void testNameShiftJis() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V30_JAPANESE, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
-                .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
-                .put(StructuredName.MIDDLE_NAME, "B")
-                .put(StructuredName.PREFIX, "Dr.")
-                .put(StructuredName.SUFFIX, "Ph.D");
-
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
-                        mContentValuesForSJis)
-                .addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
-                        Arrays.asList(
-                                "\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
-                                null, mContentValuesForSJis, null, null);
-    }
-
-    /**
-     * DoCoMo phones require all name elements should be in "family name" field.
-     */
-    public void testNameDoCoMo() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
-                .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
-                .put(StructuredName.MIDDLE_NAME, "B")
-                .put(StructuredName.PREFIX, "Dr.")
-                .put(StructuredName.SUFFIX, "Ph.D");
-
-        final String fullName = "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D";
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("N", fullName + ";;;;",
-                        Arrays.asList(fullName, "", "", "", ""),
-                        null, mContentValuesForSJis, null, null)
-                .addExpectedNode("FN", fullName, mContentValuesForSJis)
-                .addExpectedNode("SOUND", ";;;;", new TypeSet("X-IRMC-N"))
-                .addExpectedNode("TEL", "", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("ADR", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "");
-    }
-
-    private void testPhoneticNameCommon(int vcardType, String charset) {
-        mVerifier.initForExportTest(vcardType, charset);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
-
-        final ContentValues contentValues =
-            ("SHIFT_JIS".equalsIgnoreCase(charset) ?
-                    (VCardConfig.isV30(vcardType) ? mContentValuesForSJis :
-                            mContentValuesForQPAndSJis) :
-                    (VCardConfig.isV30(vcardType) ? null : mContentValuesForQPAndUtf8));
-        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
-        elem.addExpectedNode("X-PHONETIC-LAST-NAME", "\u3084\u307E\u3060",
-                        contentValues)
-                .addExpectedNode("X-PHONETIC-MIDDLE-NAME",
-                        "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0",
-                        contentValues)
-                .addExpectedNode("X-PHONETIC-FIRST-NAME", "\u305F\u308D\u3046",
-                        contentValues);
-        if (VCardConfig.isV30(vcardType)) {
-            elem.addExpectedNode("SORT-STRING",
-                    "\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 \u305F\u308D\u3046",
-                    contentValues);
-        }
-        ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE);
-        builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046")
-                .put(StructuredName.DISPLAY_NAME,
-                        "\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 " +
-                        "\u305F\u308D\u3046");
-    }
-
-    public void testPhoneticNameForJapaneseV21Utf8() {
-        testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, null);
-    }
-
-    public void testPhoneticNameForJapaneseV21Sjis() {
-        testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, "Shift_JIS");
-    }
-
-    public void testPhoneticNameForJapaneseV30Utf8() {
-        testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE, null);
-    }
-
-    public void testPhoneticNameForJapaneseV30SJis() {
-        testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE, "Shift_JIS");
-    }
-
-    public void testPhoneticNameForMobileV21_1() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
-
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("SOUND",
-                        "\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
-                        "\uFF80\uFF9B\uFF73;;;;",
-                        mContentValuesForSJis, new TypeSet("X-IRMC-N"));
-        ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE);
-        builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
-                .put(StructuredName.PHONETIC_MIDDLE_NAME,
-                        "\uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
-                .put(StructuredName.DISPLAY_NAME,
-                        "\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
-                        "\uFF80\uFF9B\uFF73");
-    }
-
-    public void testPhoneticNameForMobileV21_2() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
-
-        mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNode("SOUND", "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73;;;;",
-                                mContentValuesForSJis, new TypeSet("X-IRMC-N"));
-        ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
-                .addExpected(StructuredName.CONTENT_ITEM_TYPE);
-        builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
-                .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
-                .put(StructuredName.DISPLAY_NAME, "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73");
-    }
-
-    private void testPostalAddressWithJapaneseCommon(int vcardType, String charset) {
-        mVerifier.initForExportTest(vcardType, charset);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
-                .put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
-                .put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
-                .put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
-                .put(StructuredPostal.POSTCODE, "494-1313")
-                .put(StructuredPostal.COUNTRY, "\u65E5\u672C")
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                        "\u3053\u3093\u306A\u3068\u3053\u308D\u3092\u898B"
-                        + "\u308B\u306A\u3093\u3066\u6687\u4EBA\u3067\u3059\u304B\uFF1F")
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
-                .put(StructuredPostal.LABEL, "\u304A\u3082\u3061\u304B\u3048\u308A");
-
-        ContentValues contentValues = ("UTF-8".equalsIgnoreCase(charset) ?
-                (VCardConfig.isV30(vcardType) ? mContentValuesForSJis :
-                    mContentValuesForQPAndSJis) :
-                (VCardConfig.isV30(vcardType) ? mContentValuesForUtf8 :
-                    mContentValuesForQPAndUtf8));
-
-        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
-        // LABEL must be ignored in vCard 2.1. As for vCard 3.0, the current behavior is
-        // same as that in vCard 3.0, which can be changed in the future.
-        elem.addExpectedNode("ADR", Arrays.asList("\u79C1\u66F8\u7BB107",
-                "", "\u96DB\u898B\u6CA2\u6751", "\u9E7F\u9AA8\u5E02", "\u00D7\u00D7\u770C",
-                "494-1313", "\u65E5\u672C"),
-                contentValues);
-        mVerifier.addContentValuesVerifierElem().addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
-                .put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
-                .put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
-                .put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
-                .put(StructuredPostal.POSTCODE, "494-1313")
-                .put(StructuredPostal.COUNTRY, "\u65E5\u672C")
-                .put(StructuredPostal.FORMATTED_ADDRESS,
-                        "\u65E5\u672C 494-1313 \u00D7\u00D7\u770C \u9E7F\u9AA8\u5E02 " +
-                        "\u96DB\u898B\u6CA2\u6751 " + "\u79C1\u66F8\u7BB107")
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
-    }
-    public void testPostalAddresswithJapaneseV21() {
-        testPostalAddressWithJapaneseCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, "Shift_JIS");
-    }
-
-    /**
-     * Verifies that only one address field is emitted toward DoCoMo phones.
-     * Prefered type must (should?) be: HOME > WORK > OTHER > CUSTOM
-     */
-    public void testPostalAdrressForDoCoMo_1() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
-                .put(StructuredPostal.POBOX, "1");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
-                .put(StructuredPostal.POBOX, "2");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
-                .put(StructuredPostal.POBOX, "3");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
-                .put(StructuredPostal.LABEL, "custom")
-                .put(StructuredPostal.POBOX, "4");
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "")
-                .addExpectedNode("ADR",
-                        Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
-    }
-
-    public void testPostalAdrressForDoCoMo_2() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
-                .put(StructuredPostal.POBOX, "1");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
-                .put(StructuredPostal.POBOX, "2");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
-                .put(StructuredPostal.LABEL, "custom")
-                .put(StructuredPostal.POBOX, "3");
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "")
-                .addExpectedNode("ADR",
-                        Arrays.asList("2", "", "", "", "", "", ""), new TypeSet("WORK"));
-    }
-
-    public void testPostalAdrressForDoCoMo_3() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
-                .put(StructuredPostal.LABEL, "custom1")
-                .put(StructuredPostal.POBOX, "1");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
-                .put(StructuredPostal.POBOX, "2");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
-                .put(StructuredPostal.LABEL, "custom2")
-                .put(StructuredPostal.POBOX, "3");
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "")
-                .addExpectedNode("ADR", Arrays.asList("2", "", "", "", "", "", ""));
-    }
-
-    /**
-     * Verifies the vCard exporter tolerates null TYPE.
-     */
-    public void testPostalAdrressForDoCoMo_4() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POBOX, "1");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
-                .put(StructuredPostal.POBOX, "2");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
-                .put(StructuredPostal.POBOX, "3");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
-                .put(StructuredPostal.POBOX, "4");
-        entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
-                .put(StructuredPostal.POBOX, "5");
-
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "")
-                .addExpectedNode("ADR",
-                        Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
-    }
-
-    private void testJapanesePhoneNumberCommon(int vcardType) {
-        mVerifier.initForExportTest(vcardType);
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "0312341234")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "09012341234")
-                .put(Phone.TYPE, Phone.TYPE_MOBILE);
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
-                .addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
-    }
-
-    public void testJapanesePhoneNumberV21_1() {
-        testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE);
-    }
-
-    public void testJapanesePhoneNumberV30() {
-        testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE);
-    }
-
-    public void testJapanesePhoneNumberDoCoMo() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "0312341234")
-                .put(Phone.TYPE, Phone.TYPE_HOME);
-        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
-                .put(Phone.NUMBER, "09012341234")
-                .put(Phone.TYPE, Phone.TYPE_MOBILE);
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "")
-                .addExpectedNode("ADR", "", new TypeSet("HOME"))
-                .addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
-                .addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
-    }
-
-    public void testNoteDoCoMo() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
-        ContactEntry entry = mVerifier.addInputEntry();
-        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "note1");
-        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "note2");
-        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
-                .put(Note.NOTE, "note3");
-
-        // More than one note fields must be aggregated into one note.
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("TEL", "", new TypeSet("HOME"))
-                .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
-                .addExpectedNode("X-CLASS", "PUBLIC")
-                .addExpectedNode("X-REDUCTION", "")
-                .addExpectedNode("X-NO", "")
-                .addExpectedNode("X-DCM-HMN-MODE", "")
-                .addExpectedNode("ADR", "", new TypeSet("HOME"))
-                .addExpectedNode("NOTE", "note1\nnote2\nnote3", mContentValuesForQP);
-    }
-
-    public void testAndroidCustomV21() {
-        mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_GENERIC);
-        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
-                .put(Nickname.NAME, "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC");
-        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
-                .addExpectedNode("X-ANDROID-CUSTOM",
-                        Arrays.asList(Nickname.CONTENT_ITEM_TYPE,
-                                "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC",
-                                "", "", "", "", "", "", "", "", "", "", "", "", "", ""),
-                        mContentValuesForQPAndUtf8);
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/VCardTestsBase.java b/vcard/tests/src/com/android/vcard/tests/VCardTestsBase.java
deleted file mode 100644
index 8998b3c..0000000
--- a/vcard/tests/src/com/android/vcard/tests/VCardTestsBase.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests;
-
-import android.content.ContentValues;
-import android.test.AndroidTestCase;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.tests.test_utils.VCardVerifier;
-
-/**
- * BaseClass for vCard unit tests with utility classes.
- * Please do not add each unit test here.
- */
-/* package */ class VCardTestsBase extends AndroidTestCase {
-    public static final int V21 = VCardConfig.VCARD_TYPE_V21_GENERIC;
-    public static final int V30 = VCardConfig.VCARD_TYPE_V30_GENERIC;
-
-    // Do not modify these during tests.
-    protected final ContentValues mContentValuesForQP;
-    protected final ContentValues mContentValuesForSJis;
-    protected final ContentValues mContentValuesForUtf8;
-    protected final ContentValues mContentValuesForQPAndSJis;
-    protected final ContentValues mContentValuesForQPAndUtf8;
-    protected final ContentValues mContentValuesForBase64V21;
-    protected final ContentValues mContentValuesForBase64V30;
-
-    protected VCardVerifier mVerifier;
-    private boolean mSkipVerification;
-
-    public VCardTestsBase() {
-        super();
-        // Not using constants in vCard code since it may be wrong.
-        mContentValuesForQP = new ContentValues();
-        mContentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
-        mContentValuesForSJis = new ContentValues();
-        mContentValuesForSJis.put("CHARSET", "SHIFT_JIS");
-        mContentValuesForUtf8 = new ContentValues();
-        mContentValuesForUtf8.put("CHARSET", "UTF-8");
-        mContentValuesForQPAndSJis = new ContentValues();
-        mContentValuesForQPAndSJis.put("ENCODING", "QUOTED-PRINTABLE");
-        mContentValuesForQPAndSJis.put("CHARSET", "SHIFT_JIS");
-        mContentValuesForQPAndUtf8 = new ContentValues();
-        mContentValuesForQPAndUtf8.put("ENCODING", "QUOTED-PRINTABLE");
-        mContentValuesForQPAndUtf8.put("CHARSET", "UTF-8");
-        mContentValuesForBase64V21 = new ContentValues();
-        mContentValuesForBase64V21.put("ENCODING", "BASE64");
-        mContentValuesForBase64V30 = new ContentValues();
-        mContentValuesForBase64V30.put("ENCODING", "b");
-    }
-
-    @Override
-    public void testAndroidTestCaseSetupProperly() {
-        super.testAndroidTestCaseSetupProperly();
-        mSkipVerification = true;
-    }
-
-    @Override
-    public void setUp() throws Exception{
-        super.setUp();
-        mVerifier = new VCardVerifier(this);
-        mSkipVerification = false;
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-        if (!mSkipVerification) {
-            mVerifier.verify();
-        }
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/VCardUtilsTests.java b/vcard/tests/src/com/android/vcard/tests/VCardUtilsTests.java
deleted file mode 100644
index 732009a..0000000
--- a/vcard/tests/src/com/android/vcard/tests/VCardUtilsTests.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests;
-
-import com.android.vcard.VCardUtils;
-
-import junit.framework.TestCase;
-
-import java.util.List;
-
-public class VCardUtilsTests extends TestCase {
-    public void testContainsOnlyPrintableAscii() {
-        assertTrue(VCardUtils.containsOnlyPrintableAscii((String)null));
-        assertTrue(VCardUtils.containsOnlyPrintableAscii((String[])null));
-        assertTrue(VCardUtils.containsOnlyPrintableAscii((List<String>)null));
-        assertTrue(VCardUtils.containsOnlyPrintableAscii(""));
-        assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
-        assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
-        StringBuilder builder = new StringBuilder();
-        for (int i = 0x20; i < 0x7F; i++) {
-            builder.append((char)i);
-        }
-        assertTrue(VCardUtils.containsOnlyPrintableAscii(builder.toString()));
-        assertTrue(VCardUtils.containsOnlyPrintableAscii("\r\n"));
-        assertFalse(VCardUtils.containsOnlyPrintableAscii("\u0019"));
-        assertFalse(VCardUtils.containsOnlyPrintableAscii("\u007F"));
-    }
-
-    public void testContainsOnlyNonCrLfPrintableAscii() {
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String)null));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String[])null));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((List<String>)null));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(""));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
-        StringBuilder builder = new StringBuilder();
-        for (int i = 0x20; i < 0x7F; i++) {
-            builder.append((char)i);
-        }
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(builder.toString()));
-        assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u0019"));
-        assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u007F"));
-        assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\r"));
-        assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\n"));
-    }
-
-    public void testContainsOnlyAlphaDigitHyphen() {
-        assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String)null));
-        assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String[])null));
-        assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((List<String>)null));
-        assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen(""));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
-        assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("0123456789-"));
-        for (int i = 0; i < 0x30; i++) {
-            if (i == 0x2D) {  // -
-                continue;
-            }
-            assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
-        }
-        for (int i = 0x3A; i < 0x41; i++) {
-            assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
-        }
-        for (int i = 0x5B; i < 0x61; i++) {
-            assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
-        }
-        for (int i = 0x7B; i < 0x100; i++) {
-            assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
-        }
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ContactEntry.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ContactEntry.java
deleted file mode 100644
index dff1f051..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ContactEntry.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.Data;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * <p>
- * The class representing one contact, which should contain multiple ContentValues like
- * StructuredName, Email, etc.
- * </p>
- */
-public final class ContactEntry {
-    private final List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
-
-    public ContentValuesBuilder addContentValues(String mimeType) {
-        ContentValues contentValues = new ContentValues();
-        contentValues.put(Data.MIMETYPE, mimeType);
-        mContentValuesList.add(contentValues);
-        return new ContentValuesBuilder(contentValues);
-    }
-
-    public List<ContentValues> getList() {
-        return mContentValuesList;
-    }
-}
\ No newline at end of file
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesBuilder.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesBuilder.java
deleted file mode 100644
index fb53b8f..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesBuilder.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentValues;
-
-/**
- * ContentValues-like class which enables users to chain put() methods and restricts
- * the other methods.
- */
-public class ContentValuesBuilder {
-    private final ContentValues mContentValues;
-
-    public ContentValuesBuilder(final ContentValues contentValues) {
-        mContentValues = contentValues;
-    }
-
-    public ContentValuesBuilder put(String key, String value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Byte value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Short value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Integer value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Long value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Float value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Double value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, Boolean value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder put(String key, byte[] value) {
-        mContentValues.put(key, value);
-        return this;
-    }
-
-    public ContentValuesBuilder putNull(String key) {
-        mContentValues.putNull(key);
-        return this;
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java
deleted file mode 100644
index 2b3e3ab..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.test.AndroidTestCase;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryConstructor;
-import com.android.vcard.VCardEntryHandler;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ContentValuesVerifier implements VCardEntryHandler {
-    private AndroidTestCase mTestCase;
-    private List<ContentValuesVerifierElem> mContentValuesVerifierElemList =
-        new ArrayList<ContentValuesVerifierElem>();
-    private int mIndex;
-
-    public ContentValuesVerifierElem addElem(AndroidTestCase androidTestCase) {
-        mTestCase = androidTestCase;
-        ContentValuesVerifierElem importVerifier = new ContentValuesVerifierElem(androidTestCase);
-        mContentValuesVerifierElemList.add(importVerifier);
-        return importVerifier;
-    }
-
-    public void verify(int resId, int vCardType) throws IOException, VCardException {
-        verify(mTestCase.getContext().getResources().openRawResource(resId), vCardType);
-    }
-
-    public void verify(int resId, int vCardType, final VCardParser vCardParser)
-            throws IOException, VCardException {
-        verify(mTestCase.getContext().getResources().openRawResource(resId),
-                vCardType, vCardParser);
-    }
-
-    public void verify(InputStream is, int vCardType) throws IOException, VCardException {
-        final VCardParser vCardParser;
-        if (VCardConfig.isV30(vCardType)) {
-            vCardParser = new VCardParser_V30();
-        } else {
-            vCardParser = new VCardParser_V21();
-        }
-        verify(is, vCardType, vCardParser);
-    }
-
-    public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
-            throws IOException, VCardException {
-        VCardEntryConstructor builder = new VCardEntryConstructor(vCardType, null);
-        builder.addEntryHandler(this);
-        try {
-            vCardParser.parse(is, builder);
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                }
-            }
-        }
-    }
-
-    public void onStart() {
-        for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
-            elem.onParsingStart();
-        }
-    }
-
-    public void onEntryCreated(VCardEntry entry) {
-        mTestCase.assertTrue(mIndex < mContentValuesVerifierElemList.size());
-        mContentValuesVerifierElemList.get(mIndex).onEntryCreated(entry);
-        mIndex++;
-    }
-
-    public void onEnd() {
-        for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
-            elem.onParsingEnd();
-            elem.verifyResolver();
-        }
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifierElem.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifierElem.java
deleted file mode 100644
index 6c09693..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifierElem.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.Data;
-import android.test.AndroidTestCase;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryCommitter;
-import com.android.vcard.VCardEntryConstructor;
-import com.android.vcard.VCardEntryHandler;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public class ContentValuesVerifierElem {
-    private final AndroidTestCase mTestCase;
-    private final ImportTestResolver mResolver;
-    private final VCardEntryHandler mHandler;
-
-    public ContentValuesVerifierElem(AndroidTestCase androidTestCase) {
-        mTestCase = androidTestCase;
-        mResolver = new ImportTestResolver(androidTestCase);
-        mHandler = new VCardEntryCommitter(mResolver);
-    }
-
-    public ContentValuesBuilder addExpected(String mimeType) {
-        ContentValues contentValues = new ContentValues();
-        contentValues.put(Data.MIMETYPE, mimeType);
-        mResolver.addExpectedContentValues(contentValues);
-        return new ContentValuesBuilder(contentValues);
-    }
-
-    public void verify(int resId, int vCardType)
-            throws IOException, VCardException {
-        verify(mTestCase.getContext().getResources().openRawResource(resId), vCardType);
-    }
-
-    public void verify(InputStream is, int vCardType) throws IOException, VCardException {
-        final VCardParser vCardParser;
-        if (VCardConfig.isV30(vCardType)) {
-            vCardParser = new VCardParser_V30();
-        } else {
-            vCardParser = new VCardParser_V21();
-        }
-        final VCardEntryConstructor builder = new VCardEntryConstructor(vCardType, null);
-        builder.addEntryHandler(mHandler);
-        try {
-            vCardParser.parse(is, builder);
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                }
-            }
-        }
-        verifyResolver();
-    }
-
-    public void verifyResolver() {
-        mResolver.verify();
-    }
-
-    public void onParsingStart() {
-        mHandler.onStart();
-    }
-
-    public void onEntryCreated(VCardEntry entry) {
-        mHandler.onEntryCreated(entry);
-    }
-
-    public void onParsingEnd() {
-        mHandler.onEnd();
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ExportTestProvider.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ExportTestProvider.java
deleted file mode 100644
index caedf9d..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ExportTestProvider.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Entity;
-import android.content.EntityIterator;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.test.mock.MockContentProvider;
-import android.test.mock.MockCursor;
-
-import com.android.vcard.VCardComposer;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/* package */ class ExportTestProvider extends MockContentProvider {
-    final private TestCase mTestCase;
-    final private ArrayList<ContactEntry> mContactEntryList = new ArrayList<ContactEntry>();
-
-    private static class MockEntityIterator implements EntityIterator {
-        List<Entity> mEntityList;
-        Iterator<Entity> mIterator;
-
-        public MockEntityIterator(List<ContentValues> contentValuesList) {
-            mEntityList = new ArrayList<Entity>();
-            Entity entity = new Entity(new ContentValues());
-            for (ContentValues contentValues : contentValuesList) {
-                    entity.addSubValue(Data.CONTENT_URI, contentValues);
-            }
-            mEntityList.add(entity);
-            mIterator = mEntityList.iterator();
-        }
-
-        public boolean hasNext() {
-            return mIterator.hasNext();
-        }
-
-        public Entity next() {
-            return mIterator.next();
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException("remove not supported");
-        }
-
-        public void reset() {
-            mIterator = mEntityList.iterator();
-        }
-
-        public void close() {
-        }
-    }
-
-    public ExportTestProvider(TestCase testCase) {
-        mTestCase = testCase;
-    }
-
-    public ContactEntry buildInputEntry() {
-        ContactEntry contactEntry = new ContactEntry();
-        mContactEntryList.add(contactEntry);
-        return contactEntry;
-    }
-
-    /**
-     * <p>
-     * An old method which had existed but was removed from ContentResolver.
-     * </p>
-     * <p>
-     * We still keep using this method since we don't have a propeer way to know
-     * which value in the ContentValue corresponds to the entry in Contacts database.
-     * </p>
-     */
-    public EntityIterator queryEntities(Uri uri,
-            String selection, String[] selectionArgs, String sortOrder) {
-        mTestCase.assertTrue(uri != null);
-        mTestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
-        final String authority = uri.getAuthority();
-        mTestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
-        mTestCase.assertTrue((Data.CONTACT_ID + "=?").equals(selection));
-        mTestCase.assertEquals(1, selectionArgs.length);
-        final int id = Integer.parseInt(selectionArgs[0]);
-        mTestCase.assertTrue(id >= 0 && id < mContactEntryList.size());
-
-        return new MockEntityIterator(mContactEntryList.get(id).getList());
-    }
-
-    @Override
-    public Cursor query(Uri uri,String[] projection,
-            String selection, String[] selectionArgs, String sortOrder) {
-        mTestCase.assertTrue(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
-        // In this test, following arguments are not supported.
-        mTestCase.assertNull(selection);
-        mTestCase.assertNull(selectionArgs);
-        mTestCase.assertNull(sortOrder);
-
-        return new MockCursor() {
-            int mCurrentPosition = -1;
-
-            @Override
-            public int getCount() {
-                return mContactEntryList.size();
-            }
-
-            @Override
-            public boolean moveToFirst() {
-                mCurrentPosition = 0;
-                return true;
-            }
-
-            @Override
-            public boolean moveToNext() {
-                if (mCurrentPosition < mContactEntryList.size()) {
-                    mCurrentPosition++;
-                    return true;
-                } else {
-                    return false;
-                }
-            }
-
-            @Override
-            public boolean isBeforeFirst() {
-                return mCurrentPosition < 0;
-            }
-
-            @Override
-            public boolean isAfterLast() {
-                return mCurrentPosition >= mContactEntryList.size();
-            }
-
-            @Override
-            public int getColumnIndex(String columnName) {
-                mTestCase.assertEquals(Contacts._ID, columnName);
-                return 0;
-            }
-
-            @Override
-            public int getInt(int columnIndex) {
-                mTestCase.assertEquals(0, columnIndex);
-                mTestCase.assertTrue(mCurrentPosition >= 0
-                        && mCurrentPosition < mContactEntryList.size());
-                return mCurrentPosition;
-            }
-
-            @Override
-            public String getString(int columnIndex) {
-                return String.valueOf(getInt(columnIndex));
-            }
-
-            @Override
-            public void close() {
-            }
-        };
-    }
-}
\ No newline at end of file
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ExportTestResolver.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ExportTestResolver.java
deleted file mode 100644
index 3cd014c..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ExportTestResolver.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.provider.ContactsContract.RawContacts;
-import android.test.mock.MockContentResolver;
-
-import com.android.vcard.VCardComposer;
-
-import junit.framework.TestCase;
-
-/* package */ class ExportTestResolver extends MockContentResolver {
-    private final ExportTestProvider mProvider;
-    public ExportTestResolver(TestCase testCase) {
-        mProvider = new ExportTestProvider(testCase);
-        addProvider(VCardComposer.VCARD_TEST_AUTHORITY, mProvider);
-        addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
-    }
-
-    public ContactEntry addInputContactEntry() {
-        return mProvider.buildInputEntry();
-    }
-
-    public ExportTestProvider getProvider() {
-        return mProvider;
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java
deleted file mode 100644
index 3d7cb60..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.test.mock.MockContentProvider;
-import android.text.TextUtils;
-import android.util.Log;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.Map.Entry;
-
-/* package */ class ImportTestProvider extends MockContentProvider {
-    private static final Set<String> sKnownMimeTypeSet =
-        new HashSet<String>(Arrays.asList(StructuredName.CONTENT_ITEM_TYPE,
-                Nickname.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE,
-                Email.CONTENT_ITEM_TYPE, StructuredPostal.CONTENT_ITEM_TYPE,
-                Im.CONTENT_ITEM_TYPE, Organization.CONTENT_ITEM_TYPE,
-                Event.CONTENT_ITEM_TYPE, Photo.CONTENT_ITEM_TYPE,
-                Note.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE,
-                Relation.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
-                GroupMembership.CONTENT_ITEM_TYPE));
-
-    final Map<String, Collection<ContentValues>> mMimeTypeToExpectedContentValues;
-
-    private final TestCase mTestCase;
-
-    public ImportTestProvider(TestCase testCase) {
-        mTestCase = testCase;
-        mMimeTypeToExpectedContentValues =
-            new HashMap<String, Collection<ContentValues>>();
-        for (String acceptanbleMimeType : sKnownMimeTypeSet) {
-            // Do not use HashSet since the current implementation changes the content of
-            // ContentValues after the insertion, which make the result of hashCode()
-            // changes...
-            mMimeTypeToExpectedContentValues.put(
-                    acceptanbleMimeType, new ArrayList<ContentValues>());
-        }
-    }
-
-    public void addExpectedContentValues(ContentValues expectedContentValues) {
-        final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
-        if (!sKnownMimeTypeSet.contains(mimeType)) {
-            mTestCase.fail(String.format(
-                    "Unknow MimeType %s in the test code. Test code should be broken.",
-                    mimeType));
-        }
-
-        final Collection<ContentValues> contentValuesCollection =
-                mMimeTypeToExpectedContentValues.get(mimeType);
-        contentValuesCollection.add(expectedContentValues);
-    }
-
-    @Override
-    public ContentProviderResult[] applyBatch(
-            ArrayList<ContentProviderOperation> operations) {
-        if (operations == null) {
-            mTestCase.fail("There is no operation.");
-        }
-
-        final int size = operations.size();
-        ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
-        for (int i = 0; i < size; i++) {
-            Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
-            fakeResultArray[i] = new ContentProviderResult(uri);
-        }
-
-        for (int i = 0; i < size; i++) {
-            ContentProviderOperation operation = operations.get(i);
-            ContentValues contentValues = operation.resolveValueBackReferences(
-                    fakeResultArray, i);
-        }
-        for (int i = 0; i < size; i++) {
-            ContentProviderOperation operation = operations.get(i);
-            ContentValues actualContentValues = operation.resolveValueBackReferences(
-                    fakeResultArray, i);
-            final Uri uri = operation.getUri();
-            if (uri.equals(RawContacts.CONTENT_URI)) {
-                mTestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
-                mTestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
-            } else if (uri.equals(Data.CONTENT_URI)) {
-                final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
-                if (!sKnownMimeTypeSet.contains(mimeType)) {
-                    mTestCase.fail(String.format(
-                            "Unknown MimeType %s. Probably added after developing this test",
-                            mimeType));
-                }
-                // Remove data meaningless in this unit tests.
-                // Specifically, Data.DATA1 - DATA7 are set to null or empty String
-                // regardless of the input, but it may change depending on how
-                // resolver-related code handles it.
-                // Here, we ignore these implementation-dependent specs and
-                // just check whether vCard importer correctly inserts rellevent data.
-                Set<String> keyToBeRemoved = new HashSet<String>();
-                for (Entry<String, Object> entry : actualContentValues.valueSet()) {
-                    Object value = entry.getValue();
-                    if (value == null || TextUtils.isEmpty(value.toString())) {
-                        keyToBeRemoved.add(entry.getKey());
-                    }
-                }
-                for (String key: keyToBeRemoved) {
-                    actualContentValues.remove(key);
-                }
-                /* for testing
-                Log.d("@@@",
-                        String.format("MimeType: %s, data: %s",
-                                mimeType, actualContentValues.toString())); */
-                // Remove RAW_CONTACT_ID entry just for safety, since we do not care
-                // how resolver-related code handles the entry in this unit test,
-                if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
-                    actualContentValues.remove(Data.RAW_CONTACT_ID);
-                }
-                final Collection<ContentValues> contentValuesCollection =
-                    mMimeTypeToExpectedContentValues.get(mimeType);
-                if (contentValuesCollection.isEmpty()) {
-                    mTestCase.fail("ContentValues for MimeType " + mimeType
-                            + " is not expected at all (" + actualContentValues + ")");
-                }
-                boolean checked = false;
-                for (ContentValues expectedContentValues : contentValuesCollection) {
-                    /*for testing
-                    Log.d("@@@", "expected: "
-                            + convertToEasilyReadableString(expectedContentValues));
-                    Log.d("@@@", "actual  : "
-                            + convertToEasilyReadableString(actualContentValues));*/
-                    if (equalsForContentValues(expectedContentValues,
-                            actualContentValues)) {
-                        mTestCase.assertTrue(contentValuesCollection.remove(expectedContentValues));
-                        checked = true;
-                        break;
-                    }
-                }
-                if (!checked) {
-                    final StringBuilder builder = new StringBuilder();
-                    builder.append("Unexpected: ");
-                    builder.append(convertToEasilyReadableString(actualContentValues));
-                    builder.append("\nExpected: ");
-                    for (ContentValues expectedContentValues : contentValuesCollection) {
-                        builder.append(convertToEasilyReadableString(expectedContentValues));
-                    }
-                    mTestCase.fail(builder.toString());
-                }
-            } else {
-                mTestCase.fail("Unexpected Uri has come: " + uri);
-            }
-        }  // for (int i = 0; i < size; i++) {
-        return fakeResultArray;
-    }
-
-    public void verify() {
-        StringBuilder builder = new StringBuilder();
-        for (Collection<ContentValues> contentValuesCollection :
-                mMimeTypeToExpectedContentValues.values()) {
-            for (ContentValues expectedContentValues: contentValuesCollection) {
-                builder.append(convertToEasilyReadableString(expectedContentValues));
-                builder.append("\n");
-            }
-        }
-        if (builder.length() > 0) {
-            final String failMsg =
-                "There is(are) remaining expected ContentValues instance(s): \n"
-                    + builder.toString();
-            mTestCase.fail(failMsg);
-        }
-    }
-
-    /**
-     * Utility method to print ContentValues whose content is printed with sorted keys.
-     */
-    private String convertToEasilyReadableString(ContentValues contentValues) {
-        if (contentValues == null) {
-            return "null";
-        }
-        String mimeTypeValue = "";
-        SortedMap<String, String> sortedMap = new TreeMap<String, String>();
-        for (Entry<String, Object> entry : contentValues.valueSet()) {
-            final String key = entry.getKey();
-            final Object value = entry.getValue();
-            final String valueString = (value != null ? value.toString() : null);
-            if (Data.MIMETYPE.equals(key)) {
-                mimeTypeValue = valueString;
-            } else {
-                mTestCase.assertNotNull(key);
-                sortedMap.put(key, valueString);
-            }
-        }
-        StringBuilder builder = new StringBuilder();
-        builder.append(Data.MIMETYPE);
-        builder.append('=');
-        builder.append(mimeTypeValue);
-        for (Entry<String, String> entry : sortedMap.entrySet()) {
-            final String key = entry.getKey();
-            final String value = entry.getValue();
-            builder.append(' ');
-            builder.append(key);
-            builder.append("=\"");
-            builder.append(value);
-            builder.append('"');
-        }
-        return builder.toString();
-    }
-
-    private static boolean equalsForContentValues(
-            ContentValues expected, ContentValues actual) {
-        if (expected == actual) {
-            return true;
-        } else if (expected == null || actual == null || expected.size() != actual.size()) {
-            return false;
-        }
-
-        for (Entry<String, Object> entry : expected.valueSet()) {
-            final String key = entry.getKey();
-            final Object value = entry.getValue();
-            if (!actual.containsKey(key)) {
-                return false;
-            }
-            if (value instanceof byte[]) {
-                Object actualValue = actual.get(key);
-                if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
-                    byte[] e = (byte[])value;
-                    byte[] a = (byte[])actualValue;
-                    Log.d("@@@", "expected (len: " + e.length + "): " + Arrays.toString(e));
-                    Log.d("@@@", "actual (len: " + a.length + "): " + Arrays.toString(a));
-                    return false;
-                }
-            } else if (!value.equals(actual.get(key))) {
-                Log.d("@@@", "different.");
-                return false;
-            }
-        }
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/ImportTestResolver.java b/vcard/tests/src/com/android/vcard/tests/test_utils/ImportTestResolver.java
deleted file mode 100644
index 645e9db..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/ImportTestResolver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.provider.ContactsContract.RawContacts;
-import android.test.mock.MockContentResolver;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-
-/* package */ class ImportTestResolver extends MockContentResolver {
-    private final ImportTestProvider mProvider;
-
-    public ImportTestResolver(TestCase testCase) {
-        mProvider = new ImportTestProvider(testCase);
-    }
-
-    @Override
-    public ContentProviderResult[] applyBatch(String authority,
-            ArrayList<ContentProviderOperation> operations) {
-        equalsString(authority, RawContacts.CONTENT_URI.toString());
-        return mProvider.applyBatch(operations);
-    }
-
-    public void addExpectedContentValues(ContentValues expectedContentValues) {
-        mProvider.addExpectedContentValues(expectedContentValues);
-    }
-
-    public void verify() {
-        mProvider.verify();
-    }
-
-    private static boolean equalsString(String a, String b) {
-        if (a == null || a.length() == 0) {
-            return b == null || b.length() == 0;
-        } else {
-            return a.equals(b);
-        }
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/LineVerifier.java b/vcard/tests/src/com/android/vcard/tests/test_utils/LineVerifier.java
deleted file mode 100644
index d8cfe5b..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/LineVerifier.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import com.android.vcard.VCardComposer;
-
-import android.content.Context;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-
-public class LineVerifier implements VCardComposer.OneEntryHandler {
-    private final TestCase mTestCase;
-    private final ArrayList<LineVerifierElem> mLineVerifierElemList;
-    private int mVCardType;
-    private int index;
-
-    public LineVerifier(TestCase testCase, int vcardType) {
-        mTestCase = testCase;
-        mLineVerifierElemList = new ArrayList<LineVerifierElem>();
-        mVCardType = vcardType;
-    }
-
-    public LineVerifierElem addLineVerifierElem() {
-        LineVerifierElem lineVerifier = new LineVerifierElem(mTestCase, mVCardType);
-        mLineVerifierElemList.add(lineVerifier);
-        return lineVerifier;
-    }
-
-    public void verify(String vcard) {
-        if (index >= mLineVerifierElemList.size()) {
-            mTestCase.fail("Insufficient number of LineVerifier (" + index + ")");
-        }
-
-        LineVerifierElem lineVerifier = mLineVerifierElemList.get(index);
-        lineVerifier.verify(vcard);
-
-        index++;
-    }
-
-    public boolean onEntryCreated(String vcard) {
-        verify(vcard);
-        return true;
-    }
-
-    public boolean onInit(Context context) {
-        return true;
-    }
-
-    public void onTerminate() {
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/LineVerifierElem.java b/vcard/tests/src/com/android/vcard/tests/test_utils/LineVerifierElem.java
deleted file mode 100644
index 3ec6ba39..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/LineVerifierElem.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.text.TextUtils;
-
-import com.android.vcard.VCardConfig;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class LineVerifierElem {
-    private final TestCase mTestCase;
-    private final List<String> mExpectedLineList = new ArrayList<String>();
-    private final boolean mIsV30;
-
-    public LineVerifierElem(TestCase testCase, int vcardType) {
-        mTestCase = testCase;
-        mIsV30 = VCardConfig.isV30(vcardType);
-    }
-
-    public LineVerifierElem addExpected(final String line) {
-        if (!TextUtils.isEmpty(line)) {
-            mExpectedLineList.add(line);
-        }
-        return this;
-    }
-
-    public void verify(final String vcard) {
-        final String[] lineArray = vcard.split("\\r?\\n");
-        final int length = lineArray.length;
-        boolean beginExists = false;
-        boolean endExists = false;
-        boolean versionExists = false;
-
-        for (int i = 0; i < length; i++) {
-            final String line = lineArray[i];
-            if (TextUtils.isEmpty(line)) {
-                continue;
-            }
-
-            if ("BEGIN:VCARD".equalsIgnoreCase(line)) {
-                if (beginExists) {
-                    mTestCase.fail("Multiple \"BEGIN:VCARD\" line found");
-                } else {
-                    beginExists = true;
-                    continue;
-                }
-            } else if ("END:VCARD".equalsIgnoreCase(line)) {
-                if (endExists) {
-                    mTestCase.fail("Multiple \"END:VCARD\" line found");
-                } else {
-                    endExists = true;
-                    continue;
-                }
-            } else if ((mIsV30 ? "VERSION:3.0" : "VERSION:2.1").equalsIgnoreCase(line)) {
-                if (versionExists) {
-                    mTestCase.fail("Multiple VERSION line + found");
-                } else {
-                    versionExists = true;
-                    continue;
-                }
-            }
-
-            if (!beginExists) {
-                mTestCase.fail("Property other than BEGIN came before BEGIN property: "
-                        + line);
-            } else if (endExists) {
-                mTestCase.fail("Property other than END came after END property: "
-                        + line);
-            }
-
-            final int index = mExpectedLineList.indexOf(line);
-            if (index >= 0) {
-                mExpectedLineList.remove(index);
-            } else {
-                mTestCase.fail("Unexpected line: " + line);
-            }
-        }
-
-        if (!mExpectedLineList.isEmpty()) {
-            StringBuffer buffer = new StringBuffer();
-            for (String expectedLine : mExpectedLineList) {
-                buffer.append(expectedLine);
-                buffer.append("\n");
-            }
-
-            mTestCase.fail("Expected line(s) not found:" + buffer.toString());
-        }
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNode.java b/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNode.java
deleted file mode 100644
index 14c8d6c..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNode.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentValues;
-
-import com.android.vcard.VCardEntry;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * <p>
- * The class representing one property (e.g. "N;ENCODING=UTF-8:family:given:middle:prefix:suffix").
- * </p>
- * <p>
- * Previously used in main vCard handling code but now exists only for testing.
- * </p>
- * <p>
- * Especially useful for testing parser code (VCardParser), since all properties can be
- * checked via this class unlike {@link VCardEntry}, which only emits the result of
- * interpretation of the content of each vCard. We cannot know whether vCard parser or
- * {@link VCardEntry} is wrong without this class.
- * </p>
- */
-public class PropertyNode {
-    public String propName;
-    public String propValue;
-    public List<String> propValue_vector;
-
-    /** Store value as byte[],after decode.
-     * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
-     */
-    public byte[] propValue_bytes;
-
-    /**
-     * param store: key=paramType, value=paramValue
-     * Note that currently PropertyNode class does not support multiple param-values
-     * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
-     * one String value like "A,B", not ["A", "B"]...
-     * TODO: fix this. 
-     */
-    public ContentValues paramMap;
-
-    /** Only for TYPE=??? param store. */
-    public Set<String> paramMap_TYPE;
-
-    /** Store group values. Used only in VCard. */
-    public Set<String> propGroupSet;
-    
-    public PropertyNode() {
-        propName = "";
-        propValue = "";
-        propValue_vector = new ArrayList<String>();
-        paramMap = new ContentValues();
-        paramMap_TYPE = new HashSet<String>();
-        propGroupSet = new HashSet<String>();
-    }
-    
-    public PropertyNode(
-            String propName, String propValue, List<String> propValue_vector,
-            byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
-            Set<String> propGroupSet) {
-        if (propName != null) {
-            this.propName = propName;
-        } else {
-            this.propName = "";
-        }
-        if (propValue != null) {
-            this.propValue = propValue;
-        } else {
-            this.propValue = "";
-        }
-        if (propValue_vector != null) {
-            this.propValue_vector = propValue_vector;
-        } else {
-            this.propValue_vector = new ArrayList<String>();
-        }
-        this.propValue_bytes = propValue_bytes;
-        if (paramMap != null) {
-            this.paramMap = paramMap;
-        } else {
-            this.paramMap = new ContentValues();
-        }
-        if (paramMap_TYPE != null) {
-            this.paramMap_TYPE = paramMap_TYPE;
-        } else {
-            this.paramMap_TYPE = new HashSet<String>();
-        }
-        if (propGroupSet != null) {
-            this.propGroupSet = propGroupSet;
-        } else {
-            this.propGroupSet = new HashSet<String>();
-        }
-    }
-    
-    @Override
-    public int hashCode() {
-        // vCard may contain more than one same line in one entry, while HashSet or any other
-        // library which utilize hashCode() does not honor that, so intentionally throw an
-        // Exception.
-        throw new UnsupportedOperationException(
-                "PropertyNode does not provide hashCode() implementation intentionally.");
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof PropertyNode)) {
-            return false;
-        }
-        
-        PropertyNode node = (PropertyNode)obj;
-        
-        if (propName == null || !propName.equals(node.propName)) {
-            return false;
-        } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
-            return false;
-        } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
-            return false;
-        } else if (!propGroupSet.equals(node.propGroupSet)) {
-            return false;
-        }
-
-        if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
-            return true;
-        } else {
-            if (!propValue.equals(node.propValue)) {
-                return false;
-            }
-
-            // The value in propValue_vector is not decoded even if it should be
-            // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
-            // is 1, the encoded value is stored in propValue, so we do not have to
-            // check it.
-            return (propValue_vector.equals(node.propValue_vector) ||
-                    propValue_vector.size() == 1 ||
-                    node.propValue_vector.size() == 1);
-        }
-    }
-    
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("propName: ");
-        builder.append(propName);
-        builder.append(", paramMap: ");
-        builder.append(paramMap.toString());
-        builder.append(", paramMap_TYPE: [");
-        boolean first = true;
-        for (String elem : paramMap_TYPE) {
-            if (first) {
-                first = false;
-            } else {
-                builder.append(", ");
-            }
-            builder.append('"');
-            builder.append(elem);
-            builder.append('"');
-        }
-        builder.append("]");
-        if (!propGroupSet.isEmpty()) {
-            builder.append(", propGroupSet: [");
-            first = true;
-            for (String elem : propGroupSet) {
-                if (first) {
-                    first = false;
-                } else {
-                    builder.append(", ");
-                }
-                builder.append('"');
-                builder.append(elem);
-                builder.append('"');
-            }
-            builder.append("]");
-        }
-        if (propValue_vector != null && propValue_vector.size() > 1) {
-            builder.append(", propValue_vector size: ");
-            builder.append(propValue_vector.size());
-        }
-        if (propValue_bytes != null) {
-            builder.append(", propValue_bytes size: ");
-            builder.append(propValue_bytes.length);
-        }
-        builder.append(", propValue: \"");
-        builder.append(propValue);
-        builder.append("\"");
-        return builder.toString();
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java b/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java
deleted file mode 100644
index de33a36..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.test.AndroidTestCase;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-public class PropertyNodesVerifier extends VNodeBuilder {
-    private final List<PropertyNodesVerifierElem> mPropertyNodesVerifierElemList;
-    private final AndroidTestCase mAndroidTestCase;
-    private int mIndex;
-
-    public PropertyNodesVerifier(AndroidTestCase testCase) {
-        super();
-        mPropertyNodesVerifierElemList = new ArrayList<PropertyNodesVerifierElem>();
-        mAndroidTestCase = testCase;
-    }
-
-    public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
-        PropertyNodesVerifierElem elem = new PropertyNodesVerifierElem(mAndroidTestCase);
-        mPropertyNodesVerifierElemList.add(elem);
-        return elem;
-    }
-
-    public void verify(int resId, int vCardType)
-            throws IOException, VCardException {
-        verify(mAndroidTestCase.getContext().getResources().openRawResource(resId), vCardType);
-    }
-
-    public void verify(int resId, int vCardType, final VCardParser vCardParser)
-            throws IOException, VCardException {
-        verify(mAndroidTestCase.getContext().getResources().openRawResource(resId),
-                vCardType, vCardParser);
-    }
-
-    public void verify(InputStream is, int vCardType) throws IOException, VCardException {
-        final VCardParser vCardParser;
-        if (VCardConfig.isV30(vCardType)) {
-            vCardParser = new VCardParser_V30();
-        } else {
-            vCardParser = new VCardParser_V21();
-        }
-        verify(is, vCardType, vCardParser);
-    }
-
-    public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
-            throws IOException, VCardException {
-        try {
-            vCardParser.parse(is, this);
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                }
-            }
-        }
-    }
-
-    @Override
-    public void endEntry() {
-        super.endEntry();
-        mAndroidTestCase.assertTrue(mIndex < mPropertyNodesVerifierElemList.size());
-        mAndroidTestCase.assertTrue(mIndex < vNodeList.size());
-        mPropertyNodesVerifierElemList.get(mIndex).verify(vNodeList.get(mIndex));
-        mIndex++;
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java b/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java
deleted file mode 100644
index 6eb8498..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentValues;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * Utility class which verifies input VNode.
- *
- * This class first checks whether each propertyNode in the VNode is in the
- * "ordered expected property list".
- * If the node does not exist in the "ordered list", the class refers to
- * "unorderd expected property set" and checks the node is expected somewhere.
- */
-public class PropertyNodesVerifierElem {
-    public static class TypeSet extends HashSet<String> {
-        public TypeSet(String ... array) {
-            super(Arrays.asList(array));
-        }
-    }
-
-    public static class GroupSet extends HashSet<String> {
-        public GroupSet(String ... array) {
-            super(Arrays.asList(array));
-        }
-    }
-
-    private final HashMap<String, List<PropertyNode>> mOrderedNodeMap;
-    // Intentionally use ArrayList instead of Set, assuming there may be more than one
-    // exactly same objects.
-    private final ArrayList<PropertyNode> mUnorderedNodeList;
-    private final TestCase mTestCase;
-
-    public PropertyNodesVerifierElem(TestCase testCase) {
-        mOrderedNodeMap = new HashMap<String, List<PropertyNode>>();
-        mUnorderedNodeList = new ArrayList<PropertyNode>();
-        mTestCase = testCase;
-    }
-
-    // WithOrder
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue) {
-        return addExpectedNodeWithOrder(propName, propValue, null, null, null, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(
-            String propName, String propValue, ContentValues contentValues) {
-        return addExpectedNodeWithOrder(propName, propValue, null,
-                null, contentValues, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(
-            String propName, List<String> propValueList, ContentValues contentValues) {
-        return addExpectedNodeWithOrder(propName, null, propValueList,
-                null, contentValues, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(
-            String propName, String propValue, List<String> propValueList) {
-        return addExpectedNodeWithOrder(propName, propValue, propValueList, null,
-                null, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(
-            String propName, List<String> propValueList) {
-        final String propValue = concatinateListWithSemiColon(propValueList);
-        return addExpectedNodeWithOrder(propName, propValue.toString(), propValueList,
-                null, null, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
-            TypeSet paramMap_TYPE) {
-        return addExpectedNodeWithOrder(propName, propValue, null,
-                null, null, paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName,
-            List<String> propValueList, TypeSet paramMap_TYPE) {
-        return addExpectedNodeWithOrder(propName, null, propValueList, null, null,
-                paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
-            ContentValues paramMap, TypeSet paramMap_TYPE) {
-        return addExpectedNodeWithOrder(propName, propValue, null, null,
-                paramMap, paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
-            List<String> propValueList, TypeSet paramMap_TYPE) {
-        return addExpectedNodeWithOrder(propName, propValue, propValueList, null, null,
-                paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
-            List<String> propValueList, byte[] propValue_bytes,
-            ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
-        if (propValue == null && propValueList != null) {
-            propValue = concatinateListWithSemiColon(propValueList);
-        }
-        PropertyNode propertyNode = new PropertyNode(propName,
-                propValue, propValueList, propValue_bytes,
-                paramMap, paramMap_TYPE, propGroupSet);
-        List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
-        if (expectedNodeList == null) {
-            expectedNodeList = new ArrayList<PropertyNode>();
-            mOrderedNodeMap.put(propName, expectedNodeList);
-        }
-        expectedNodeList.add(propertyNode);
-        return this;
-    }
-
-    // WithoutOrder
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue) {
-        return addExpectedNode(propName, propValue, null, null, null, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
-            ContentValues contentValues) {
-        return addExpectedNode(propName, propValue, null, null, contentValues, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName,
-            List<String> propValueList, ContentValues contentValues) {
-        return addExpectedNode(propName, null,
-                propValueList, null, contentValues, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
-            List<String> propValueList) {
-        return addExpectedNode(propName, propValue, propValueList, null, null, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName,
-            List<String> propValueList) {
-        return addExpectedNode(propName, null, propValueList,
-                null, null, null, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
-            TypeSet paramMap_TYPE) {
-        return addExpectedNode(propName, propValue, null, null, null, paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName,
-            List<String> propValueList, TypeSet paramMap_TYPE) {
-        final String propValue = concatinateListWithSemiColon(propValueList);
-        return addExpectedNode(propName, propValue, propValueList, null, null,
-                paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
-            List<String> propValueList, TypeSet paramMap_TYPE) {
-        return addExpectedNode(propName, propValue, propValueList, null, null,
-                paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
-            ContentValues paramMap, TypeSet paramMap_TYPE) {
-        return addExpectedNode(propName, propValue, null, null,
-                paramMap, paramMap_TYPE, null);
-    }
-
-    public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
-            List<String> propValueList, byte[] propValue_bytes,
-            ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
-        if (propValue == null && propValueList != null) {
-            propValue = concatinateListWithSemiColon(propValueList);
-        }
-        mUnorderedNodeList.add(new PropertyNode(propName, propValue,
-                propValueList, propValue_bytes, paramMap, paramMap_TYPE, propGroupSet));
-        return this;
-    }
-
-    public void verify(VNode vnode) {
-        for (PropertyNode actualNode : vnode.propList) {
-            verifyNode(actualNode.propName, actualNode);
-        }
-        if (!mOrderedNodeMap.isEmpty() || !mUnorderedNodeList.isEmpty()) {
-            List<String> expectedProps = new ArrayList<String>();
-            for (List<PropertyNode> nodes : mOrderedNodeMap.values()) {
-                for (PropertyNode node : nodes) {
-                    if (!expectedProps.contains(node.propName)) {
-                        expectedProps.add(node.propName);
-                    }
-                }
-            }
-            for (PropertyNode node : mUnorderedNodeList) {
-                if (!expectedProps.contains(node.propName)) {
-                    expectedProps.add(node.propName);
-                }
-            }
-            mTestCase.fail("Expected property " + Arrays.toString(expectedProps.toArray())
-                    + " was not found.");
-        }
-    }
-
-    private void verifyNode(final String propName, final PropertyNode actualNode) {
-        List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
-        final int size = (expectedNodeList != null ? expectedNodeList.size() : 0);
-        if (size > 0) {
-            for (int i = 0; i < size; i++) {
-                PropertyNode expectedNode = expectedNodeList.get(i);
-                List<PropertyNode> expectedButDifferentValueList = new ArrayList<PropertyNode>();
-                if (expectedNode.propName.equals(propName)) {
-                    if (expectedNode.equals(actualNode)) {
-                        expectedNodeList.remove(i);
-                        if (expectedNodeList.size() == 0) {
-                            mOrderedNodeMap.remove(propName);
-                        }
-                        return;
-                    } else {
-                        expectedButDifferentValueList.add(expectedNode);
-                    }
-                }
-
-                // "actualNode" is not in ordered expected list.
-                // Try looking over unordered expected list.
-                if (tryFoundExpectedNodeFromUnorderedList(actualNode,
-                        expectedButDifferentValueList)) {
-                    return;
-                }
-
-                if (!expectedButDifferentValueList.isEmpty()) {
-                    // Same propName exists but with different value(s).
-                    failWithExpectedNodeList(propName, actualNode,
-                            expectedButDifferentValueList);
-                } else {
-                    // There's no expected node with same propName.
-                    mTestCase.fail("Unexpected property \"" + propName + "\" exists.");
-                }
-            }
-        } else {
-            List<PropertyNode> expectedButDifferentValueList =
-                new ArrayList<PropertyNode>();
-            if (tryFoundExpectedNodeFromUnorderedList(actualNode, expectedButDifferentValueList)) {
-                return;
-            } else {
-                if (!expectedButDifferentValueList.isEmpty()) {
-                    // Same propName exists but with different value(s).
-                    failWithExpectedNodeList(propName, actualNode,
-                            expectedButDifferentValueList);
-                } else {
-                    // There's no expected node with same propName.
-                    mTestCase.fail("Unexpected property \"" + propName + "\" exists.");
-                }
-            }
-        }
-    }
-
-    private String concatinateListWithSemiColon(List<String> array) {
-        StringBuffer buffer = new StringBuffer();
-        boolean first = true;
-        for (String propValueElem : array) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(';');
-            }
-            buffer.append(propValueElem);
-        }
-
-        return buffer.toString();
-    }
-
-    private boolean tryFoundExpectedNodeFromUnorderedList(PropertyNode actualNode,
-            List<PropertyNode> expectedButDifferentValueList) {
-        final String propName = actualNode.propName;
-        int unorderedListSize = mUnorderedNodeList.size();
-        for (int i = 0; i < unorderedListSize; i++) {
-            PropertyNode unorderedExpectedNode = mUnorderedNodeList.get(i);
-            if (unorderedExpectedNode.propName.equals(propName)) {
-                if (unorderedExpectedNode.equals(actualNode)) {
-                    mUnorderedNodeList.remove(i);
-                    return true;
-                }
-                expectedButDifferentValueList.add(unorderedExpectedNode);
-            }
-        }
-        return false;
-    }
-
-    private void failWithExpectedNodeList(String propName, PropertyNode actualNode,
-            List<PropertyNode> expectedNodeList) {
-        StringBuilder builder = new StringBuilder();
-        for (PropertyNode expectedNode : expectedNodeList) {
-            builder.append("expected: ");
-            builder.append(expectedNode.toString());
-            builder.append("\n");
-        }
-        mTestCase.fail("Property \"" + propName + "\" has wrong value.\n"
-                + builder.toString()
-                + "  actual: " + actualNode.toString());
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java b/vcard/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java
deleted file mode 100644
index 87d82d2..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.EntityIterator;
-import android.net.Uri;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContext;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.vcard.VCardComposer;
-import com.android.vcard.VCardConfig;
-import com.android.vcard.VCardEntryConstructor;
-import com.android.vcard.VCardInterpreter;
-import com.android.vcard.VCardInterpreterCollection;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.exception.VCardException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-
-/**
- * <p>
- * The class lets users checks that given expected vCard data are same as given actual vCard data.
- * Able to verify both vCard importer/exporter.
- * </p>
- * <p>
- * First a user has to initialize the object by calling either
- * {@link #initForImportTest(int, int)} or {@link #initForExportTest(int)}.
- * "Round trip test" (import -> export -> import, or export -> import -> export) is not supported.
- * </p>
- */
-public class VCardVerifier {
-    private static final String LOG_TAG = "VCardVerifier";
-
-    private static class CustomMockContext extends MockContext {
-        final ContentResolver mResolver;
-        public CustomMockContext(ContentResolver resolver) {
-            mResolver = resolver;
-        }
-
-        @Override
-        public ContentResolver getContentResolver() {
-            return mResolver;
-        }
-    }
-
-    private class VCardVerifierInternal implements VCardComposer.OneEntryHandler {
-        public boolean onInit(Context context) {
-            return true;
-        }
-        public boolean onEntryCreated(String vcard) {
-            verifyOneVCard(vcard);
-            return true;
-        }
-        public void onTerminate() {
-        }
-    }
-
-    private final AndroidTestCase mTestCase;
-    private final VCardVerifierInternal mVCardVerifierInternal;
-    private int mVCardType;
-    private boolean mIsV30;
-    private boolean mIsDoCoMo;
-
-    // Only one of them must be non-empty.
-    private ExportTestResolver mExportTestResolver;
-    private InputStream mInputStream;
-
-    // To allow duplication, use list instead of set.
-    // When null, we don't need to do the verification.
-    private PropertyNodesVerifier mPropertyNodesVerifier;
-    private LineVerifier mLineVerifier;
-    private ContentValuesVerifier mContentValuesVerifier;
-    private boolean mInitialized;
-    private boolean mVerified = false;
-    private String mCharset;
-
-    // Called by VCardTestsBase
-    public VCardVerifier(AndroidTestCase testCase) {
-        mTestCase = testCase;
-        mVCardVerifierInternal = new VCardVerifierInternal();
-        mExportTestResolver = null;
-        mInputStream = null;
-        mInitialized = false;
-        mVerified = false;
-    }
-
-    // Should be called at the beginning of each import test.
-    public void initForImportTest(int vcardType, int resId) {
-        if (mInitialized) {
-            mTestCase.fail("Already initialized");
-        }
-        mVCardType = vcardType;
-        mIsV30 = VCardConfig.isV30(vcardType);
-        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
-        setInputResourceId(resId);
-        mInitialized = true;
-    }
-
-    // Should be called at the beginning of each export test.
-    public void initForExportTest(int vcardType) {
-        initForExportTest(vcardType, "UTF-8");
-    }
-
-    public void initForExportTest(int vcardType, String charset) {
-        if (mInitialized) {
-            mTestCase.fail("Already initialized");
-        }
-        mExportTestResolver = new ExportTestResolver(mTestCase);
-        mVCardType = vcardType;
-        mIsV30 = VCardConfig.isV30(vcardType);
-        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
-        mInitialized = true;
-        if (TextUtils.isEmpty(charset)) {
-            mCharset = "UTF-8";
-        } else {
-            mCharset = charset;
-        }
-    }
-
-    private void setInputResourceId(int resId) {
-        InputStream inputStream = mTestCase.getContext().getResources().openRawResource(resId);
-        if (inputStream == null) {
-            mTestCase.fail("Wrong resId: " + resId);
-        }
-        setInputStream(inputStream);
-    }
-
-    private void setInputStream(InputStream inputStream) {
-        if (mExportTestResolver != null) {
-            mTestCase.fail("addInputEntry() is called.");
-        } else if (mInputStream != null) {
-            mTestCase.fail("InputStream is already set");
-        }
-        mInputStream = inputStream;
-    }
-
-    public ContactEntry addInputEntry() {
-        if (!mInitialized) {
-            mTestCase.fail("Not initialized");
-        }
-        if (mInputStream != null) {
-            mTestCase.fail("setInputStream is called");
-        }
-        return mExportTestResolver.addInputContactEntry();
-    }
-
-    public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
-        if (!mInitialized) {
-            mTestCase.fail("Not initialized");
-        }
-        if (mPropertyNodesVerifier == null) {
-            mPropertyNodesVerifier = new PropertyNodesVerifier(mTestCase);
-        }
-        PropertyNodesVerifierElem elem =
-                mPropertyNodesVerifier.addPropertyNodesVerifierElem();
-        elem.addExpectedNodeWithOrder("VERSION", (mIsV30 ? "3.0" : "2.1"));
-
-        return elem;
-    }
-
-    public PropertyNodesVerifierElem addPropertyNodesVerifierElemWithEmptyName() {
-        if (!mInitialized) {
-            mTestCase.fail("Not initialized");
-        }
-        PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem();
-        if (mIsV30) {
-            elem.addExpectedNodeWithOrder("N", "").addExpectedNodeWithOrder("FN", "");
-        } else if (mIsDoCoMo) {
-            elem.addExpectedNodeWithOrder("N", "");
-        }
-        return elem;
-    }
-
-    public LineVerifierElem addLineVerifierElem() {
-        if (!mInitialized) {
-            mTestCase.fail("Not initialized");
-        }
-        if (mLineVerifier == null) {
-            mLineVerifier = new LineVerifier(mTestCase, mVCardType);
-        }
-        return mLineVerifier.addLineVerifierElem();
-    }
-
-    public ContentValuesVerifierElem addContentValuesVerifierElem() {
-        if (!mInitialized) {
-            mTestCase.fail("Not initialized");
-        }
-        if (mContentValuesVerifier == null) {
-            mContentValuesVerifier = new ContentValuesVerifier();
-        }
-
-        return mContentValuesVerifier.addElem(mTestCase);
-    }
-
-    private void verifyOneVCard(final String vcard) {
-        Log.d(LOG_TAG, vcard);
-        final VCardInterpreter builder;
-        if (mContentValuesVerifier != null) {
-            final VNodeBuilder vnodeBuilder = mPropertyNodesVerifier;
-            final VCardEntryConstructor vcardDataBuilder =
-                    new VCardEntryConstructor(mVCardType);
-            vcardDataBuilder.addEntryHandler(mContentValuesVerifier);
-            if (mPropertyNodesVerifier != null) {
-                builder = new VCardInterpreterCollection(Arrays.asList(
-                        mPropertyNodesVerifier, vcardDataBuilder));
-            } else {
-                builder = vnodeBuilder;
-            }
-        } else {
-            if (mPropertyNodesVerifier != null) {
-                builder = mPropertyNodesVerifier;
-            } else {
-                return;
-            }
-        }
-
-        InputStream is = null;
-        try {
-            // Note: we must not specify charset toward vCard parsers. This code checks whether
-            // those parsers are able to encode given binary without any extra information for
-            // charset.
-            final VCardParser parser = (mIsV30 ?
-                    new VCardParser_V30(mVCardType) : new VCardParser_V21(mVCardType));
-            is = new ByteArrayInputStream(vcard.getBytes(mCharset));
-            parser.parse(is, builder);
-        } catch (IOException e) {
-            mTestCase.fail("Unexpected IOException: " + e.getMessage());
-        } catch (VCardException e) {
-            mTestCase.fail("Unexpected VCardException: " + e.getMessage());
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                    mTestCase.fail("Unexpected IOException: " + e.getMessage());
-                }
-            }
-        }
-    }
-
-    public void verify() {
-        if (!mInitialized) {
-            mTestCase.fail("Not initialized.");
-        }
-        if (mVerified) {
-            mTestCase.fail("verify() was called twice.");
-        }
-        if (mInputStream != null) {
-            try {
-                verifyForImportTest();
-            } catch (IOException e) {
-                mTestCase.fail("IOException was thrown: " + e.getMessage());
-            } catch (VCardException e) {
-                mTestCase.fail("VCardException was thrown: " + e.getMessage());
-            }
-        } else if (mExportTestResolver != null){
-            verifyForExportTest();
-        } else {
-            mTestCase.fail("No input is determined");
-        }
-        mVerified = true;
-    }
-
-    private void verifyForImportTest() throws IOException, VCardException {
-        if (mLineVerifier != null) {
-            mTestCase.fail("Not supported now.");
-        }
-        if (mContentValuesVerifier != null) {
-            mContentValuesVerifier.verify(mInputStream, mVCardType);
-        }
-    }
-
-    public static EntityIterator mockGetEntityIteratorMethod(
-            final ContentResolver resolver,
-            final Uri uri, final String selection,
-            final String[] selectionArgs, final String sortOrder) {
-        if (ExportTestResolver.class.equals(resolver.getClass())) {
-            return ((ExportTestResolver)resolver).getProvider().queryEntities(
-                    uri, selection, selectionArgs, sortOrder);
-        }
-
-        Log.e(LOG_TAG, "Unexpected provider given.");
-        return null;
-    }
-
-    private Method getMockGetEntityIteratorMethod()
-            throws SecurityException, NoSuchMethodException {
-        return this.getClass().getMethod("mockGetEntityIteratorMethod",
-                ContentResolver.class, Uri.class, String.class, String[].class, String.class);
-    }
-
-    private void verifyForExportTest() {
-       final VCardComposer composer =
-            new VCardComposer(new CustomMockContext(mExportTestResolver), mVCardType, mCharset);
-        composer.addHandler(mLineVerifier);
-        composer.addHandler(mVCardVerifierInternal);
-        if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
-            mTestCase.fail("init() failed. Reason: " + composer.getErrorReason());
-        }
-        mTestCase.assertFalse(composer.isAfterLast());
-        try {
-            while (!composer.isAfterLast()) {
-                try {
-                    final Method mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod();
-                    mTestCase.assertNotNull(mockGetEntityIteratorMethod);
-                    mTestCase.assertTrue(composer.createOneEntry(mockGetEntityIteratorMethod));
-                } catch (Exception e) {
-                    e.printStackTrace();
-                    mTestCase.fail();
-                }
-            }
-        } finally {
-            composer.terminate();
-        }
-    }
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/VNode.java b/vcard/tests/src/com/android/vcard/tests/test_utils/VNode.java
deleted file mode 100644
index 2ca762b..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/VNode.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import java.util.ArrayList;
-
-/**
- * Previously used in main vCard handling code but now exists only for testing.
- */
-public class VNode {
-    public String VName;
-
-    public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
-
-    /** 0:parse over. 1:parsing. */
-    public int parseStatus = 1;
-}
diff --git a/vcard/tests/src/com/android/vcard/tests/test_utils/VNodeBuilder.java b/vcard/tests/src/com/android/vcard/tests/test_utils/VNodeBuilder.java
deleted file mode 100644
index 77a28ad..0000000
--- a/vcard/tests/src/com/android/vcard/tests/test_utils/VNodeBuilder.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.vcard.tests.test_utils;
-
-import android.content.ContentValues;
-import android.util.Base64;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.VCardInterpreter;
-import com.android.vcard.VCardUtils;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * <p>
- * The class storing the parse result to custom datastruct:
- * {@link VNode}, and {@link PropertyNode}.
- * Maybe several vcard instance, so use vNodeList to store.
- * </p>
- * <p>
- * This is called VNode, not VCardNode, since it was used for expressing vCalendar (iCal).
- * </p>
- */
-/* package */ class VNodeBuilder implements VCardInterpreter {
-    static private String LOG_TAG = "VNodeBuilder"; 
-    
-    public List<VNode> vNodeList = new ArrayList<VNode>();
-    private int mNodeListPos = 0;
-    private VNode mCurrentVNode;
-    private PropertyNode mCurrentPropNode;
-    private String mCurrentParamType;
-
-    /**
-     * The charset using which VParser parses the text.
-     */
-    private String mSourceCharset;
-
-    /**
-     * The charset with which byte array is encoded to String.
-     */
-    private String mTargetCharset;
-    
-    private boolean mStrictLineBreakParsing;
-    
-    public VNodeBuilder() {
-        this(VCardConfig.DEFAULT_IMPORT_CHARSET, false);
-    }
-
-    public VNodeBuilder(String targetCharset, boolean strictLineBreakParsing) {
-        mSourceCharset = VCardConfig.DEFAULT_INTERMEDIATE_CHARSET;
-        if (targetCharset != null) {
-            mTargetCharset = targetCharset;
-        } else {
-            mTargetCharset = VCardConfig.DEFAULT_IMPORT_CHARSET;
-        }
-        mStrictLineBreakParsing = strictLineBreakParsing;
-    }
-
-    public void start() {
-    }
-
-    public void end() {
-    }
-
-    // Note: I guess that this code assumes the Record may nest like this:
-    // START:VPOS
-    // ...
-    // START:VPOS2
-    // ...
-    // END:VPOS2
-    // ...
-    // END:VPOS
-    //
-    // However the following code has a bug.
-    // When error occurs after calling startRecord(), the entry which is probably
-    // the cause of the error remains to be in vNodeList, while endRecord() is not called.
-    //
-    // I leave this code as is since I'm not familiar with vcalendar specification.
-    // But I believe we should refactor this code in the future.
-    // Until this, the last entry has to be removed when some error occurs.
-    public void startEntry() {
-        VNode vnode = new VNode();
-        vnode.parseStatus = 1;
-        vnode.VName = "VCARD";
-        // I feel this should be done in endRecord(), but it cannot be done because of
-        // the reason above.
-        vNodeList.add(vnode);
-        mNodeListPos = vNodeList.size() - 1;
-        mCurrentVNode = vNodeList.get(mNodeListPos);
-    }
-
-    public void endEntry() {
-        VNode endNode = vNodeList.get(mNodeListPos);
-        endNode.parseStatus = 0;
-        while(mNodeListPos > 0){
-            mNodeListPos--;
-            if((vNodeList.get(mNodeListPos)).parseStatus == 1)
-                break;
-        }
-        mCurrentVNode = vNodeList.get(mNodeListPos);
-    }
-
-    public void startProperty() {
-        mCurrentPropNode = new PropertyNode();
-    }
-
-    public void endProperty() {
-        mCurrentVNode.propList.add(mCurrentPropNode);
-    }
-    
-    public void propertyName(String name) {
-        mCurrentPropNode.propName = name;
-    }
-
-    public void propertyGroup(String group) {
-        mCurrentPropNode.propGroupSet.add(group);
-    }
-    
-    public void propertyParamType(String type) {
-        mCurrentParamType = type;
-    }
-
-    public void propertyParamValue(String value) {
-        if (mCurrentParamType == null ||
-                mCurrentParamType.equalsIgnoreCase("TYPE")) {
-            mCurrentPropNode.paramMap_TYPE.add(value);
-        } else {
-            mCurrentPropNode.paramMap.put(mCurrentParamType, value);
-        }
-
-        mCurrentParamType = null;
-    }
-
-    private String encodeString(String originalString, String targetCharset) {
-        if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
-            return originalString;
-        }
-        Charset charset = Charset.forName(mSourceCharset);
-        ByteBuffer byteBuffer = charset.encode(originalString);
-        // byteBuffer.array() "may" return byte array which is larger than
-        // byteBuffer.remaining(). Here, we keep on the safe side.
-        byte[] bytes = new byte[byteBuffer.remaining()];
-        byteBuffer.get(bytes);
-        try {
-            return new String(bytes, targetCharset);
-        } catch (UnsupportedEncodingException e) {
-            Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
-            return null;
-        }
-    }
-    
-    private String handleOneValue(String value, String targetCharset, String encoding) {
-        if (encoding != null) {
-            encoding = encoding.toUpperCase();
-            if (encoding.equals("BASE64") || encoding.equals("B")) {
-                // Assume BASE64 is used only when the number of values is 1.
-                mCurrentPropNode.propValue_bytes = Base64.decode(value.getBytes(), Base64.NO_WRAP);
-                return value;
-            } else if (encoding.equals("QUOTED-PRINTABLE")) {
-                return VCardUtils.parseQuotedPrintable(
-                        value, mStrictLineBreakParsing, mSourceCharset, targetCharset);
-            }
-            // Unknown encoding. Fall back to default.
-        }
-        return encodeString(value, targetCharset);
-    }
-    
-    public void propertyValues(List<String> values) {
-        if (values == null || values.size() == 0) {
-            mCurrentPropNode.propValue_bytes = null;
-            mCurrentPropNode.propValue_vector.clear();
-            mCurrentPropNode.propValue_vector.add("");
-            mCurrentPropNode.propValue = "";
-            return;
-        }
-        
-        ContentValues paramMap = mCurrentPropNode.paramMap;
-        
-        String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET")); 
-        String encoding = paramMap.getAsString("ENCODING"); 
-        
-        if (targetCharset == null || targetCharset.length() == 0) {
-            targetCharset = mTargetCharset;
-        }
-        
-        for (String value : values) {
-            mCurrentPropNode.propValue_vector.add(
-                    handleOneValue(value, targetCharset, encoding));
-        }
-
-        mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
-    }
-
-    private String listToString(List<String> list){
-        int size = list.size();
-        if (size > 1) {
-            StringBuilder typeListB = new StringBuilder();
-            for (String type : list) {
-                typeListB.append(type).append(";");
-            }
-            int len = typeListB.length();
-            if (len > 0 && typeListB.charAt(len - 1) == ';') {
-                return typeListB.substring(0, len - 1);
-            }
-            return typeListB.toString();
-        } else if (size == 1) {
-            return list.get(0);
-        } else {
-            return "";
-        }
-    }
-    
-    public String getResult(){
-        throw new RuntimeException("Not supported");
-    }
-}