Merge change 5645 into donut

* changes:
  Added a new operation mode where user can launch all tests under a folder from test app ui.
diff --git a/Android.mk b/Android.mk
index 0e8793d..f32129e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -82,6 +82,7 @@
 	core/java/android/app/IWallpaperService.aidl \
 	core/java/android/app/IWallpaperServiceCallback.aidl \
 	core/java/android/backup/IBackupManager.aidl \
+	core/java/android/backup/IRestoreObserver.aidl \
 	core/java/android/backup/IRestoreSession.aidl \
 	core/java/android/bluetooth/IBluetoothA2dp.aidl \
 	core/java/android/bluetooth/IBluetoothDevice.aidl \
diff --git a/api/current.xml b/api/current.xml
index b28780c..673d053 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -3452,50 +3452,6 @@
  visibility="public"
 >
 </field>
-<field name="donut_resource_pad26"
- type="int"
- transient="false"
- volatile="false"
- value="16843398"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="donut_resource_pad27"
- type="int"
- transient="false"
- volatile="false"
- value="16843397"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="donut_resource_pad28"
- type="int"
- transient="false"
- volatile="false"
- value="16843396"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="donut_resource_pad29"
- type="int"
- transient="false"
- volatile="false"
- value="16843395"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="donut_resource_pad3"
  type="int"
  transient="false"
@@ -3672,6 +3628,17 @@
  visibility="public"
 >
 </field>
+<field name="dropDownHeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843395"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="dropDownHintAppearance"
  type="int"
  transient="false"
@@ -5311,6 +5278,17 @@
  visibility="public"
 >
 </field>
+<field name="largeScreens"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843398"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="launchMode"
  type="int"
  transient="false"
@@ -6191,6 +6169,17 @@
  visibility="public"
 >
 </field>
+<field name="normalScreens"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843397"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="numColumns"
  type="int"
  transient="false"
@@ -7577,6 +7566,17 @@
  visibility="public"
 >
 </field>
+<field name="smallScreens"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843396"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="smoothScrollbar"
  type="int"
  transient="false"
@@ -22088,6 +22088,19 @@
 <parameter name="position" type="int">
 </parameter>
 </method>
+<method name="itemForPosition"
+ return="android.app.LauncherActivity.ListItem"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
 <method name="makeListItems"
  return="java.util.List&lt;android.app.LauncherActivity.ListItem&gt;"
  abstract="false"
@@ -22196,6 +22209,16 @@
  visibility="public"
 >
 </field>
+<field name="resolveInfo"
+ type="android.content.pm.ResolveInfo"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="ListActivity"
  extends="android.app.Activity"
@@ -23852,6 +23875,17 @@
  visibility="public"
 >
 </field>
+<field name="USER_QUERY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;user_query&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <interface name="SearchManager.OnCancelListener"
  abstract="true"
@@ -34787,6 +34821,17 @@
  visibility="public"
 >
 </field>
+<field name="CONFIG_SCREEN_LAYOUT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CONFIG_TOUCHSCREEN"
  type="int"
  transient="false"
@@ -35255,6 +35300,28 @@
  type="int"
  transient="false"
  volatile="false"
+ value="2048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_SUPPORTS_NORMAL_SCREENS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_SUPPORTS_SMALL_SCREENS"
+ type="int"
+ transient="false"
+ volatile="false"
  value="512"
  static="true"
  final="true"
@@ -39454,6 +39521,50 @@
  visibility="public"
 >
 </field>
+<field name="SCREENLAYOUT_LARGE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREENLAYOUT_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREENLAYOUT_SMALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREENLAYOUT_UNDEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TOUCHSCREEN_FINGER"
  type="int"
  transient="false"
@@ -39588,6 +39699,16 @@
  visibility="public"
 >
 </field>
+<field name="screenLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="touchscreen"
  type="int"
  transient="false"
@@ -71778,6 +71899,721 @@
  visibility="public"
 >
 </field>
+<field name="TONE_CDMA_ABBR_ALERT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="97"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ABBR_INTERCEPT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="37"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ABBR_REORDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="39"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ALERT_AUTOREDIAL_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="87"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ALERT_CALL_GUARD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="93"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ALERT_INCALL_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="91"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ALERT_NETWORK_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="86"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ANSWER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="42"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALLDROP_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="95"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="46"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="45"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_PAT3"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="48"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_PAT5"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="50"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_PAT6"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="51"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_PAT7"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="52"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="49"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_CONFIRM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="41"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_DIAL_TONE_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="34"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_EMERGENCY_RINGBACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="92"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_L"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="53"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_PBX_L"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="71"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_PBX_SLS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="80"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_PBX_SS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="74"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_PBX_SSL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="77"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_PBX_S_X4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="83"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_SLS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_SS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="56"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_SSL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="59"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_SS_2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="62"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_HIGH_S_X4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="68"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_INTERCEPT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="36"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_KEYPAD_VOLUME_KEY_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="89"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_L"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="55"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_PBX_L"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="73"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_PBX_SLS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="82"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_PBX_SS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="76"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_PBX_SSL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="79"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_PBX_S_X4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="85"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_SLS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="67"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_SS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="58"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_SSL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="61"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_SS_2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_LOW_S_X4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="70"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_L"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="54"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_PBX_L"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="72"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_PBX_SLS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="81"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_PBX_SS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="75"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_PBX_SSL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="78"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_PBX_S_X4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="84"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_SLS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="66"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_SS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="57"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_SSL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="60"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_SS_2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="63"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_MED_S_X4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="69"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_NETWORK_BUSY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="40"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_NETWORK_BUSY_ONE_SHOT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_NETWORK_CALLWAITING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="43"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_NETWORK_USA_RINGBACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="35"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_ONE_MIN_BEEP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="88"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_PIP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="44"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_PRESSHOLDKEY_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="90"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_REORDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="38"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_SIGNAL_OFF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="98"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_CDMA_SOFT_ERROR_LITE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="94"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TONE_DTMF_0"
  type="int"
  transient="false"
@@ -138652,6 +139488,19 @@
  visibility="public"
 >
 </method>
+<method name="buildDrawingCache"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="autoScale" type="boolean">
+</parameter>
+</method>
 <method name="cancelLongPress"
  return="void"
  abstract="false"
@@ -139228,6 +140077,19 @@
  visibility="public"
 >
 </method>
+<method name="getDrawingCache"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="autoScale" type="boolean">
+</parameter>
+</method>
 <method name="getDrawingCacheBackgroundColor"
  return="int"
  abstract="false"
@@ -161435,6 +162297,17 @@
  visibility="public"
 >
 </method>
+<method name="getDropDownHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDropDownWidth"
  return="int"
  abstract="false"
@@ -161658,6 +162531,19 @@
 <parameter name="id" type="int">
 </parameter>
 </method>
+<method name="setDropDownHeight"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="height" type="int">
+</parameter>
+</method>
 <method name="setDropDownWidth"
  return="void"
  abstract="false"
@@ -179827,7 +180713,7 @@
 <method name="startMethodTracing"
  return="void"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="true"
  final="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 7852c13..105d4d2 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -32,6 +32,7 @@
 #include <media/AudioSystem.h>
 #include "CameraService.h"
 
+#include <cutils/atomic.h>
 #include <cutils/properties.h>
 
 namespace android {
@@ -81,6 +82,7 @@
     BnCameraService()
 {
     LOGI("CameraService started: pid=%d", getpid());
+    mUsers = 0;
 }
 
 CameraService::~CameraService()
@@ -96,7 +98,7 @@
     LOGD("CameraService::connect E (pid %d, client %p)", callingPid,
             cameraClient->asBinder().get());
 
-    Mutex::Autolock lock(mLock);
+    Mutex::Autolock lock(mServiceLock);
     sp<Client> client;
     if (mClient != 0) {
         sp<Client> currentClient = mClient.promote();
@@ -113,7 +115,7 @@
                     "(old pid %d, old client %p)",
                     callingPid, cameraClient->asBinder().get(),
                     currentClient->mClientPid, currentCameraClient->asBinder().get());
-                if (kill(currentClient->mClientPid, 0) == ESRCH) {
+                if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) {
                     LOGD("The old client is dead!");
                 }
                 return client;
@@ -126,6 +128,11 @@
         }
     }
 
+    if (mUsers > 0) {
+        LOGD("Still have client, rejected");
+        return client;
+    }
+
     // create a new Client object
     client = new Client(this, cameraClient, callingPid);
     mClient = client;
@@ -146,7 +153,7 @@
     // destructor won't be called with the lock held.
     sp<Client> client;
 
-    Mutex::Autolock lock(mLock);
+    Mutex::Autolock lock(mServiceLock);
 
     if (mClient == 0) {
         // This happens when we have already disconnected.
@@ -174,6 +181,20 @@
     LOGD("removeClient (pid %d) done", callingPid);
 }
 
+// The reason we need this count is a new CameraService::connect() request may
+// come in while the previous Client's destructor has not been run or is still
+// running. If the last strong reference of the previous Client is gone but
+// destructor has not been run, we should not allow the new Client to be created
+// because we need to wait for the previous Client to tear down the hardware
+// first.
+void CameraService::incUsers() {
+    android_atomic_inc(&mUsers);
+}
+
+void CameraService::decUsers() {
+    android_atomic_dec(&mUsers);
+}
+
 static sp<MediaPlayer> newMediaPlayer(const char *file) 
 {
     sp<MediaPlayer> mp = new MediaPlayer();
@@ -209,6 +230,7 @@
 
     // Callback is disabled by default
     mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    cameraService->incUsers();
     LOGD("Client::Client X (pid %d)", callingPid);
 }
 
@@ -350,7 +372,7 @@
 
 void CameraService::Client::disconnect()
 {
-    int callingPid = getCallingPid();    
+    int callingPid = getCallingPid();
 
     LOGD("Client::disconnect() E (pid %d client %p)",
             callingPid, getCameraClient()->asBinder().get());
@@ -365,18 +387,23 @@
         return;
     }
 
-    mCameraService->removeClient(mCameraClient);
-    if (mHardware != 0) {
-        LOGD("hardware teardown");
-        // Before destroying mHardware, we must make sure it's in the
-        // idle state.
-        mHardware->stopPreview();
-        // Cancel all picture callbacks.
-        mHardware->cancelPicture(true, true, true);
-        // Release the hardware resources.
-        mHardware->release();
-    }
+    // Make sure disconnect() is done once and once only, whether it is called
+    // from the user directly, or called by the destructor.
+    if (mHardware == 0) return;
+
+    LOGD("hardware teardown");
+    // Before destroying mHardware, we must make sure it's in the
+    // idle state.
+    mHardware->stopPreview();
+    // Cancel all picture callbacks.
+    mHardware->cancelPicture(true, true, true);
+    // Release the hardware resources.
+    mHardware->release();
     mHardware.clear();
+
+    mCameraService->removeClient(mCameraClient);
+    mCameraService->decUsers();
+
     LOGD("Client::disconnect() X (pid %d)", callingPid);
 }
 
@@ -634,7 +661,7 @@
     sp<Client> client = 0;
     CameraService *service = static_cast<CameraService*>(user);
     if (service != NULL) {
-        Mutex::Autolock ourLock(service->mLock);
+        Mutex::Autolock ourLock(service->mServiceLock);
         if (service->mClient != 0) {
             client = service->mClient.promote();
             if (client == 0) {
@@ -1077,7 +1104,7 @@
         result.append(buffer);
         write(fd, result.string(), result.size());
     } else {
-        AutoMutex lock(&mLock);
+        AutoMutex lock(&mServiceLock);
         if (mClient != 0) {
             sp<Client> currentClient = mClient.promote();
             sprintf(buffer, "Client (%p) PID: %d\n",
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index a421fd3..8b8b54c 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -194,7 +194,12 @@
                             CameraService();
     virtual                 ~CameraService();
 
-    mutable     Mutex                       mLock;
+    // We use a count for number of clients (shoule only be 0 or 1).
+    volatile    int32_t                     mUsers;
+    virtual     void                        incUsers();
+    virtual     void                        decUsers();
+
+    mutable     Mutex                       mServiceLock;
                 wp<Client>                  mClient;
 
 #if DEBUG_HEAP_LEAKS
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 2a4a672..3782136 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,10 +26,13 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.view.IWindowManager;
 
+import java.io.File;
+import java.io.FileNotFoundException;
 import java.util.Iterator;
 import java.util.Set;
 
@@ -446,6 +449,8 @@
             return;
         }
         
+        ParcelFileDescriptor fd = null;
+        
         String cmd = nextArg();
         if ("start".equals(cmd)) {
             start = true;
@@ -455,6 +460,16 @@
                 showUsage();
                 return;
             }
+            try {
+                fd = ParcelFileDescriptor.open(
+                        new File(profileFile),
+                        ParcelFileDescriptor.MODE_CREATE |
+                        ParcelFileDescriptor.MODE_TRUNCATE |
+                        ParcelFileDescriptor.MODE_READ_WRITE);
+            } catch (FileNotFoundException e) {
+                System.err.println("Error: Unable to open file: " + profileFile);
+                return;
+            }
         } else if (!"stop".equals(cmd)) {
             System.err.println("Error: Profile command " + cmd + " not valid");
             showUsage();
@@ -462,8 +477,8 @@
         }
         
         try {
-            if (!mAm.profileControl(process, start, profileFile)) {
-                System.out.println("PROFILE FAILED on process " + process);
+            if (!mAm.profileControl(process, start, profileFile, fd)) {
+                System.err.println("PROFILE FAILED on process " + process);
                 return;
             }
         } catch (IllegalArgumentException e) {
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 841e3df..c90b862 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -17,6 +17,7 @@
 package com.android.commands.bmgr;
 
 import android.backup.IBackupManager;
+import android.backup.IRestoreObserver;
 import android.backup.IRestoreSession;
 import android.backup.RestoreSet;
 import android.os.RemoteException;
@@ -61,6 +62,16 @@
         String op = args[0];
         mNextArg = 1;
 
+        if ("enabled".equals(op)) {
+            doEnabled();
+            return;
+        }
+
+        if ("enable".equals(op)) {
+            doEnable();
+            return;
+        }
+
         if ("run".equals(op)) {
             doRun();
             return;
@@ -90,6 +101,41 @@
         showUsage();
     }
 
+    private String enableToString(boolean enabled) {
+        return enabled ? "enabled" : "disabled";
+    }
+
+    private void doEnabled() {
+        try {
+            boolean isEnabled = mBmgr.isBackupEnabled();
+            System.out.println("Backup Manager currently "
+                    + enableToString(isEnabled));
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+        }
+    }
+
+    private void doEnable() {
+        String arg = nextArg();
+        if (arg == null) {
+            showUsage();
+            return;
+        }
+
+        try {
+            boolean enable = Boolean.parseBoolean(arg);
+            mBmgr.setBackupEnabled(enable);
+            System.out.println("Backup Manager now " + enableToString(enable));
+        } catch (NumberFormatException e) {
+            showUsage();
+            return;
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+        }
+    }
+
     private void doRun() {
         try {
             mBmgr.backupNow();
@@ -123,11 +169,14 @@
 
     private void doTransport() {
         try {
-            int which = Integer.parseInt(nextArg());
-            int old = mBmgr.selectBackupTransport(which);
-            System.out.println("Selected transport " + which + " (formerly " + old + ")");
-        } catch (NumberFormatException e) {
-            showUsage();
+            String which = nextArg();
+            String old = mBmgr.selectBackupTransport(which);
+            if (old == null) {
+                System.out.println("Unknown transport '" + which
+                        + "' specified; no changes made.");
+            } else {
+                System.out.println("Selected transport " + which + " (formerly " + old + ")");
+            }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -143,7 +192,7 @@
 
         // The rest of the 'list' options work with a restore session on the current transport
         try {
-            int curTransport = mBmgr.getCurrentTransport();
+            String curTransport = mBmgr.getCurrentTransport();
             mRestore = mBmgr.beginRestoreSession(curTransport);
             if (mRestore == null) {
                 System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -152,6 +201,8 @@
 
             if ("sets".equals(arg)) {
                 doListRestoreSets();
+            } else if ("transports".equals(arg)) {
+                doListTransports();
             }
 
             mRestore.endRestoreSession();
@@ -162,6 +213,22 @@
     }
 
     private void doListTransports() {
+        try {
+            String current = mBmgr.getCurrentTransport();
+            String[] transports = mBmgr.listAllTransports();
+            if (transports == null || transports.length == 0) {
+                System.out.println("No transports available.");
+                return;
+            }
+
+            for (String t : transports) {
+                String pad = (t.equals(current)) ? "  * " : "    ";
+                System.out.println(pad + t);
+            }
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+        }
     }
 
     private void doListRestoreSets() {
@@ -170,9 +237,7 @@
             if (sets == null || sets.length == 0) {
                 System.out.println("No restore sets available");
             } else {
-                for (RestoreSet s : sets) {
-                    System.out.println("  " + s.token + " : " + s.name);
-                }
+                printRestoreSets(sets);
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
@@ -180,17 +245,45 @@
         }
     }
 
+    private void printRestoreSets(RestoreSet[] sets) {
+        for (RestoreSet s : sets) {
+            System.out.println("  " + s.token + " : " + s.name);
+        }
+    }
+
+    class RestoreObserver extends IRestoreObserver.Stub {
+        boolean done;
+        public void restoreStarting(int numPackages) {
+            System.out.println("restoreStarting: " + numPackages + " packages");
+        }
+
+        public void onUpdate(int nowBeingRestored) {
+            System.out.println("onUpdate: " + nowBeingRestored);
+        }
+
+        public void restoreFinished(int error) {
+            System.out.println("restoreFinished: " + error);
+            synchronized (this) {
+                done = true;
+                this.notify();
+            }
+        }
+    }
+
     private void doRestore() {
-        int token;
+        long token;
         try {
-            token = Integer.parseInt(nextArg());
+            token = Long.parseLong(nextArg());
         } catch (NumberFormatException e) {
             showUsage();
             return;
         }
 
+        RestoreObserver observer = new RestoreObserver();
+
         try {
-            int curTransport = mBmgr.getCurrentTransport();
+            boolean didRestore = false;
+            String curTransport = mBmgr.getCurrentTransport();
             mRestore = mBmgr.beginRestoreSession(curTransport);
             if (mRestore == null) {
                 System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -200,15 +293,35 @@
             for (RestoreSet s : sets) {
                 if (s.token == token) {
                     System.out.println("Scheduling restore: " + s.name);
-                    mRestore.performRestore(token);
+                    mRestore.performRestore(token, observer);
+                    didRestore = true;
                     break;
                 }
             }
+            if (!didRestore) {
+                if (sets == null || sets.length == 0) {
+                    System.out.println("No available restore sets; no restore performed");
+                } else {
+                    System.out.println("No matching restore set token.  Available sets:");
+                    printRestoreSets(sets);
+                }
+            }
             mRestore.endRestoreSession();
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(BMGR_NOT_RUNNING_ERR);
         }
+
+        // now wait for it to be done
+        synchronized (observer) {
+            while (!observer.done) {
+                try {
+                    observer.wait();
+                } catch (InterruptedException ex) {
+                }
+            }
+        }
+        System.out.println("done");
     }
 
     private String nextArg() {
@@ -222,11 +335,43 @@
 
     private static void showUsage() {
         System.err.println("usage: bmgr [backup|restore|list|transport|run]");
-        System.err.println("       bmgr backup [-f] package");
+        System.err.println("       bmgr backup PACKAGE");
+        System.err.println("       bmgr enable BOOL");
+        System.err.println("       bmgr enabled");
+        System.err.println("       bmgr list transports");
         System.err.println("       bmgr list sets");
-        System.err.println("       #bmgr list transports");
-        System.err.println("       #bmgr transport which#");
-        System.err.println("       bmgr restore token#");
+        System.err.println("       bmgr transport WHICH");
+        System.err.println("       bmgr restore TOKEN");
         System.err.println("       bmgr run");
+        System.err.println("");
+        System.err.println("The 'backup' command schedules a backup pass for the named package.");
+        System.err.println("Note that the backup pass will effectively be a no-op if the package");
+        System.err.println("does not actually have changed data to store.");
+        System.err.println("");
+        System.err.println("The 'enable' command enables or disables the entire backup mechanism.");
+        System.err.println("If the argument is 'true' it will be enabled, otherwise it will be");
+        System.err.println("disabled.  When disabled, neither backup or restore operations will");
+        System.err.println("be performed.");
+        System.err.println("");
+        System.err.println("The 'enabled' command reports the current enabled/disabled state of");
+        System.err.println("the backup mechanism.");
+        System.err.println("");
+        System.err.println("The 'list transports' command reports the names of the backup transports");
+        System.err.println("currently available on the device.  These names can be passed as arguments");
+        System.err.println("to the 'transport' command.  The currently selected transport is indicated");
+        System.err.println("with a '*' character.");
+        System.err.println("");
+        System.err.println("The 'list sets' command reports the token and name of each restore set");
+        System.err.println("available to the device via the current transport.");
+        System.err.println("");
+        System.err.println("The 'transport' command designates the named transport as the currently");
+        System.err.println("active one.  This setting is persistent across reboots.");
+        System.err.println("");
+        System.err.println("The 'restore' command initiates a restore operation, using the restore set");
+        System.err.println("from the current transport whose token matches the argument.");
+        System.err.println("");
+        System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
+        System.err.println("immediately, without the usual waiting period for batching together");
+        System.err.println("data changes.");
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b6f855a2..dfa8139 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -986,7 +986,9 @@
             String process = data.readString();
             boolean start = data.readInt() != 0;
             String path = data.readString();
-            boolean res = profileControl(process, start, path);
+            ParcelFileDescriptor fd = data.readInt() != 0
+                    ? data.readFileDescriptor() : null;
+            boolean res = profileControl(process, start, path, fd);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -2232,7 +2234,7 @@
     }
     
     public boolean profileControl(String process, boolean start,
-            String path) throws RemoteException
+            String path, ParcelFileDescriptor fd) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2240,6 +2242,12 @@
         data.writeString(process);
         data.writeInt(start ? 1 : 0);
         data.writeString(path);
+        if (fd != null) {
+            data.writeInt(1);
+            fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        } else {
+            data.writeInt(0);
+        }
         mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 98bd45a..62dc651 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -48,6 +48,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -74,6 +75,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -1236,6 +1238,11 @@
         String who;
     }
 
+    private static final class ProfilerControlData {
+        String path;
+        ParcelFileDescriptor fd;
+    }
+
     private final class ApplicationThread extends ApplicationThreadNative {
         private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
         private static final String ONE_COUNT_COLUMN = "%17s %8d";
@@ -1494,8 +1501,11 @@
             }
         }
         
-        public void profilerControl(boolean start, String path) {
-            queueOrSendMessage(H.PROFILER_CONTROL, path, start ? 1 : 0);
+        public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
+            ProfilerControlData pcd = new ProfilerControlData();
+            pcd.path = path;
+            pcd.fd = fd;
+            queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
         }
 
         public void setSchedulingGroup(int group) {
@@ -1838,7 +1848,7 @@
                     handleActivityConfigurationChanged((IBinder)msg.obj);
                     break;
                 case PROFILER_CONTROL:
-                    handleProfilerControl(msg.arg1 != 0, (String)msg.obj);
+                    handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj);
                     break;
                 case CREATE_BACKUP_AGENT:
                     handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
@@ -3618,15 +3628,20 @@
         performConfigurationChanged(r.activity, mConfiguration);
     }
 
-    final void handleProfilerControl(boolean start, String path) {
+    final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
         if (start) {
-            File file = new File(path);
-            file.getParentFile().mkdirs();
             try {
-                Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
+                Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
+                        8 * 1024 * 1024, 0);
             } catch (RuntimeException e) {
-                Log.w(TAG, "Profiling failed on path " + path
+                Log.w(TAG, "Profiling failed on path " + pcd.path
                         + " -- can the process access this path?");
+            } finally {
+                try {
+                    pcd.fd.close();
+                } catch (IOException e) {
+                    Log.w(TAG, "Failure closing profile fd", e);
+                }
             }
         } else {
             Debug.stopMethodTracing();
@@ -3682,6 +3697,13 @@
          */
         Locale.setDefault(data.config.locale);
 
+        /*
+         * Update the system configuration since its preloaded and might not
+         * reflect configuration changes. The configuration object passed
+         * in AppBindData can be safely assumed to be up to date
+         */
+        Resources.getSystem().updateConfiguration(mConfiguration, null);
+
         data.info = getPackageInfoNoCheck(data.appInfo);
 
         if (data.debugMode != IApplicationThread.DEBUG_OFF) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 4b64c94..b052c99 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -26,6 +26,7 @@
 import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -331,7 +332,9 @@
             data.enforceInterface(IApplicationThread.descriptor);
             boolean start = data.readInt() != 0;
             String path = data.readString();
-            profilerControl(start, path);
+            ParcelFileDescriptor fd = data.readInt() != 0
+                    ? data.readFileDescriptor() : null;
+            profilerControl(start, path, fd);
             return true;
         }
         
@@ -711,11 +714,18 @@
         data.recycle();
     }
     
-    public void profilerControl(boolean start, String path) throws RemoteException {
+    public void profilerControl(boolean start, String path,
+            ParcelFileDescriptor fd) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeInt(start ? 1 : 0);
         data.writeString(path);
+        if (fd != null) {
+            data.writeInt(1);
+            fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        } else {
+            data.writeInt(0);
+        }
         mRemote.transact(PROFILER_CONTROL_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/BackupAgent.java b/core/java/android/app/BackupAgent.java
index e810775..0ac8a1e 100644
--- a/core/java/android/app/BackupAgent.java
+++ b/core/java/android/app/BackupAgent.java
@@ -67,7 +67,7 @@
      *                 here after writing the requested data to dataFd.
      */
     public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-             ParcelFileDescriptor newState);
+             ParcelFileDescriptor newState) throws IOException;
     
     /**
      * The application is being restored from backup, and should replace any
@@ -120,6 +120,9 @@
             BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
             try {
                 BackupAgent.this.onBackup(oldState, output, newState);
+            } catch (IOException ex) {
+                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
+                throw new RuntimeException(ex);
             } catch (RuntimeException ex) {
                 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
                 throw ex;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 66bc85b..3ec7938 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -250,7 +250,7 @@
     
     // Turn on/off profiling in a particular process.
     public boolean profileControl(String process, boolean start,
-            String path) throws RemoteException;
+            String path, ParcelFileDescriptor fd) throws RemoteException;
     
     public boolean shutdown(int timeout) throws RemoteException;
     
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 029c650..c0bc2a0 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -25,6 +25,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
@@ -92,7 +93,8 @@
     void scheduleLowMemory() throws RemoteException;
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
     void requestPss() throws RemoteException;
-    void profilerControl(boolean start, String path) throws RemoteException;
+    void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
+            throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
     
     String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 8d249da..accdda9 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -60,26 +60,20 @@
      * An item in the list
      */
     public static class ListItem {
+        public ResolveInfo resolveInfo;
         public CharSequence label;
-        //public CharSequence description;
         public Drawable icon;
         public String packageName;
         public String className;
         public Bundle extras;
         
         ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
+            this.resolveInfo = resolveInfo;
             label = resolveInfo.loadLabel(pm);
             if (label == null && resolveInfo.activityInfo != null) {
                 label = resolveInfo.activityInfo.name;
             }
             
-            /*
-            if (resolveInfo.activityInfo != null &&
-                    resolveInfo.activityInfo.applicationInfo != null) {
-                description = resolveInfo.activityInfo.applicationInfo.loadDescription(pm);
-            }
-            */
-            
             icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
             packageName = resolveInfo.activityInfo.applicationInfo.packageName;
             className = resolveInfo.activityInfo.name;
@@ -122,6 +116,14 @@
             return intent;
         }
 
+        public ListItem itemForPosition(int position) {
+            if (mActivitiesList == null) {
+                return null;
+            }
+
+            return mActivitiesList.get(position);
+        }
+
         public int getCount() {
             return mActivitiesList != null ? mActivitiesList.size() : 0;
         }
@@ -354,6 +356,16 @@
     }
     
     /**
+     * Return the {@link ListItem} for a specific position in our
+     * {@link android.widget.ListView}.
+     * @param position The item to return
+     */
+    protected ListItem itemForPosition(int position) {
+        ActivityAdapter adapter = (ActivityAdapter) mAdapter;
+        return adapter.itemForPosition(position);
+    }
+    
+    /**
      * Get the base intent to use when running
      * {@link PackageManager#queryIntentActivities(Intent, int)}.
      */
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 6c7bcda..6fe4896 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -33,7 +33,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -107,7 +106,7 @@
     private Button mGoButton;
     private ImageButton mVoiceButton;
     private View mSearchPlate;
-    private AnimationDrawable mWorkingSpinner;
+    private Drawable mWorkingSpinner;
 
     // interaction with searchable application
     private SearchableInfo mSearchable;
@@ -188,7 +187,7 @@
         mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
         mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn);
         mSearchPlate = findViewById(com.android.internal.R.id.search_plate);
-        mWorkingSpinner = (AnimationDrawable) getContext().getResources().
+        mWorkingSpinner = getContext().getResources().
                 getDrawable(com.android.internal.R.drawable.search_spinner);
         
         // attach listeners
@@ -423,11 +422,11 @@
         if (working) {
             mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
                     null, null, mWorkingSpinner, null);
-            mWorkingSpinner.start();
+//            mWorkingSpinner.start();
         } else {
             mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
                     null, null, null, null);
-            mWorkingSpinner.stop();
+//            mWorkingSpinner.stop();
         }
     }
     
@@ -560,12 +559,8 @@
 
         if (mGlobalSearchMode) {
             mSearchAutoComplete.setDropDownAlwaysVisible(true);  // fill space until results come in
-            mSearchAutoComplete.setDropDownBackgroundResource(
-                    com.android.internal.R.drawable.search_dropdown_background);
         } else {
             mSearchAutoComplete.setDropDownAlwaysVisible(false);
-            mSearchAutoComplete.setDropDownBackgroundResource(
-                    com.android.internal.R.drawable.search_dropdown_background_apps);
         }
 
         // attach the suggestions adapter, if suggestions are available
@@ -605,7 +600,7 @@
                     mSearchPlate.getPaddingBottom());
         } else {
             PackageManager pm = getContext().getPackageManager();
-            Drawable icon = null;
+            Drawable icon;
             try {
                 ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0);
                 icon = pm.getApplicationIcon(info.applicationInfo);
@@ -1326,6 +1321,7 @@
 
         String query = intent.getStringExtra(SearchManager.QUERY);
         setUserQuery(query);
+        mSearchAutoComplete.showDropDown();
     }
 
     /**
@@ -1474,6 +1470,7 @@
         if (data != null) {
             intent.setData(data);
         }
+        intent.putExtra(SearchManager.USER_QUERY, mUserQuery);
         if (query != null) {
             intent.putExtra(SearchManager.QUERY, query);
         }
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index fd69ba4..e5ba6a4 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1136,6 +1136,20 @@
     public final static String QUERY = "query";
 
     /**
+     * Intent extra data key: Use this key with
+     * {@link android.content.Intent#getStringExtra
+     *  content.Intent.getStringExtra()}
+     * to obtain the query string typed in by the user.
+     * This may be different from the value of {@link #QUERY}
+     * if the intent is the result of selecting a suggestion.
+     * In that case, {@link #QUERY} will contain the value of
+     * {@link #SUGGEST_COLUMN_QUERY} for the suggestion, and
+     * {@link #USER_QUERY} will contain the string typed by the
+     * user.
+     */
+    public final static String USER_QUERY = "user_query";
+
+    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getBundleExtra
      *  content.Intent.getBundleExtra()}
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 0bdb10b..49c94d1 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -147,7 +147,7 @@
             final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query);
             // trigger fill window so the spinner stays up until the results are copied over and
             // closer to being ready
-            if (!mGlobalSearchMode) cursor.getCount();
+            if (!mGlobalSearchMode && cursor != null) cursor.getCount();
             return cursor;
         } catch (RuntimeException e) {
             Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
diff --git a/core/java/android/backup/AbsoluteFileBackupHelper.java b/core/java/android/backup/AbsoluteFileBackupHelper.java
new file mode 100644
index 0000000..ab24675
--- /dev/null
+++ b/core/java/android/backup/AbsoluteFileBackupHelper.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.backup;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileDescriptor;
+
+/**
+ * Like FileBackupHelper, but takes absolute paths for the files instead of
+ * subpaths of getFilesDir()
+ *
+ * @hide
+ */
+public class AbsoluteFileBackupHelper extends FileBackupHelperBase implements BackupHelper {
+    private static final String TAG = "AbsoluteFileBackupHelper";
+
+    Context mContext;
+    String[] mFiles;
+
+    public AbsoluteFileBackupHelper(Context context, String... files) {
+        super(context);
+
+        mContext = context;
+        mFiles = files;
+    }
+
+    /**
+     * Based on oldState, determine which of the files from the application's data directory
+     * need to be backed up, write them to the data stream, and fill in newState with the
+     * state as it exists now.
+     */
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) {
+        // use the file paths as the keys, too
+        performBackup_checked(oldState, data, newState, mFiles, mFiles);
+    }
+
+    public void restoreEntity(BackupDataInputStream data) {
+        // TODO: turn this off before ship
+        Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
+        String key = data.getKey();
+        if (isKeyInList(key, mFiles)) {
+            File f = new File(key);
+            writeFile(f, data);
+        }
+    }
+}
+
diff --git a/core/java/android/backup/BackupHelperAgent.java b/core/java/android/backup/BackupHelperAgent.java
index 3720d50..5d0c4a2 100644
--- a/core/java/android/backup/BackupHelperAgent.java
+++ b/core/java/android/backup/BackupHelperAgent.java
@@ -34,7 +34,7 @@
 
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-             ParcelFileDescriptor newState) {
+             ParcelFileDescriptor newState) throws IOException {
         mDispatcher.performBackup(oldState, data, newState);
     }
 
diff --git a/core/java/android/backup/BackupHelperDispatcher.java b/core/java/android/backup/BackupHelperDispatcher.java
index b25c3e3..6ccb83e 100644
--- a/core/java/android/backup/BackupHelperDispatcher.java
+++ b/core/java/android/backup/BackupHelperDispatcher.java
@@ -19,7 +19,10 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.IOException;
+import java.io.FileDescriptor;
 import java.util.TreeMap;
 import java.util.Map;
 
@@ -27,6 +30,11 @@
 public class BackupHelperDispatcher {
     private static final String TAG = "BackupHelperDispatcher";
 
+    private static class Header {
+        int chunkSize; // not including the header
+        String keyPrefix;
+    }
+
     TreeMap<String,BackupHelper> mHelpers = new TreeMap<String,BackupHelper>();
     
     public BackupHelperDispatcher() {
@@ -36,13 +44,63 @@
         mHelpers.put(keyPrefix, helper);
     }
 
-    /** TODO: Make this save and restore the key prefix. */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-             ParcelFileDescriptor newState) {
-        // Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
-        for (Map.Entry<String,BackupHelper> entry: mHelpers.entrySet()) {
-            data.setKeyPrefix(entry.getKey());
-            entry.getValue().performBackup(oldState, data, newState);
+             ParcelFileDescriptor newState) throws IOException {
+        // First, do the helpers that we've already done, since they're already in the state
+        // file.
+        int err;
+        Header header = new Header();
+        TreeMap<String,BackupHelper> helpers = (TreeMap<String,BackupHelper>)mHelpers.clone();
+        FileDescriptor oldStateFD = null;
+        FileDescriptor newStateFD = newState.getFileDescriptor();
+
+        if (oldState != null) {
+            oldStateFD = oldState.getFileDescriptor();
+            while ((err = readHeader_native(header, oldStateFD)) >= 0) {
+                if (err == 0) {
+                    BackupHelper helper = helpers.get(header.keyPrefix);
+                    Log.d(TAG, "handling existing helper '" + header.keyPrefix + "' " + helper);
+                    if (helper != null) {
+                        doOneBackup(oldState, data, newState, header, helper);
+                        helpers.remove(header.keyPrefix);
+                    } else {
+                        skipChunk_native(oldStateFD, header.chunkSize);
+                    }
+                }
+            }
+        }
+
+        // Then go through and do the rest that we haven't done.
+        for (Map.Entry<String,BackupHelper> entry: helpers.entrySet()) {
+            header.keyPrefix = entry.getKey();
+            Log.d(TAG, "handling new helper '" + header.keyPrefix + "'");
+            BackupHelper helper = entry.getValue();
+            doOneBackup(oldState, data, newState, header, helper);
+        }
+    }
+
+    private void doOneBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState, Header header, BackupHelper helper) 
+            throws IOException {
+        int err;
+        FileDescriptor newStateFD = newState.getFileDescriptor();
+
+        // allocate space for the header in the file
+        int pos = allocateHeader_native(header, newStateFD);
+        if (pos < 0) {
+            throw new IOException("allocateHeader_native failed (error " + pos + ")");
+        }
+
+        data.setKeyPrefix(header.keyPrefix);
+
+        // do the backup
+        helper.performBackup(oldState, data, newState);
+
+        // fill in the header (seeking back to pos).  The file pointer will be returned to
+        // where it was at the end of performBackup.  Header.chunkSize will not be filled in.
+        err = writeHeader_native(header, newStateFD, pos);
+        if (err != 0) {
+            throw new IOException("writeHeader_native failed (error " + err + ")");
         }
     }
 
@@ -83,5 +141,11 @@
             helper.writeRestoreSnapshot(newState);
         }
     }
+
+    private static native int readHeader_native(Header h, FileDescriptor fd);
+    private static native int skipChunk_native(FileDescriptor fd, int bytesToSkip);
+
+    private static native int allocateHeader_native(Header h, FileDescriptor fd);
+    private static native int writeHeader_native(Header h, FileDescriptor fd, int pos);
 }
 
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index 8df7eae..5b4ac0d 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -68,9 +68,11 @@
      * {@link android.app.BackupAgent} subclass will be scheduled when you call this method.
      */
     public void dataChanged() {
-        try {
-            mService.dataChanged(mContext.getPackageName());
-        } catch (RemoteException e) {
+        if (mService != null) {
+            try {
+                mService.dataChanged(mContext.getPackageName());
+            } catch (RemoteException e) {
+            }
         }
     }
 
@@ -81,11 +83,13 @@
      *
      * {@hide}
      */
-    public IRestoreSession beginRestoreSession(int transportID) {
+    public IRestoreSession beginRestoreSession(String transport) {
         IRestoreSession binder = null;
-        try {
-            binder = mService.beginRestoreSession(transportID);
-        } catch (RemoteException e) {
+        if (mService != null) {
+            try {
+                binder = mService.beginRestoreSession(transport);
+            } catch (RemoteException e) {
+            }
         }
         return binder;
     }
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index d6283d0..1f11762 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -48,6 +48,24 @@
     void agentDisconnected(String packageName);
 
     /**
+     * Enable/disable the backup service entirely.  When disabled, no backup
+     * or restore operations will take place.  Data-changed notifications will
+     * still be observed and collected, however, so that changes made while the
+     * mechanism was disabled will still be backed up properly if it is enabled
+     * at some point in the future.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     */
+    void setBackupEnabled(boolean isEnabled);
+
+    /**
+     * Report whether the backup mechanism is currently enabled.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     */
+    boolean isBackupEnabled();
+
+    /**
      * Schedule an immediate backup attempt for all pending updates.  This is
      * primarily intended for transports to use when they detect a suitable
      * opportunity for doing a backup pass.  If there are no pending updates to
@@ -63,23 +81,32 @@
      * Identify the currently selected transport.  Callers must hold the
      * android.permission.BACKUP permission to use this method.
      */
-    int getCurrentTransport();
+    String getCurrentTransport();
 
     /**
-     * Specify a default backup transport.  Callers must hold the
+     * Request a list of all available backup transports' names.  Callers must
+     * hold the android.permission.BACKUP permission to use this method.
+     */
+    String[] listAllTransports();
+
+    /**
+     * Specify the current backup transport.  Callers must hold the
      * android.permission.BACKUP permission to use this method.
      *
-     * @param transportID The ID of the transport to select.  This should be one
+     * @param transport The name of the transport to select.  This should be one
      * of {@link BackupManager.TRANSPORT_GOOGLE} or {@link BackupManager.TRANSPORT_ADB}.
-     * @return The ID of the previously selected transport.
+     * @return The name of the previously selected transport.  If the given transport
+     *   name is not one of the currently available transports, no change is made to
+     *   the current transport setting and the method returns null.
      */
-    int selectBackupTransport(int transportID);
+    String selectBackupTransport(String transport);
 
     /**
      * Begin a restore session with the given transport (which may differ from the
      * currently-active backup transport).
      *
+     * @param transport The name of the transport to use for the restore operation.
      * @return An interface to the restore session, or null on error.
      */
-    IRestoreSession beginRestoreSession(int transportID);
+    IRestoreSession beginRestoreSession(String transportID);
 }
diff --git a/core/java/android/backup/IRestoreObserver.aidl b/core/java/android/backup/IRestoreObserver.aidl
new file mode 100644
index 0000000..59e59fc
--- /dev/null
+++ b/core/java/android/backup/IRestoreObserver.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.backup;
+
+/**
+ * Callback class for receiving progress reports during a restore operation.
+ *
+ * @hide
+ */
+interface IRestoreObserver {
+    /**
+     * The restore operation has begun.
+     *
+     * @param numPackages The total number of packages being processed in
+     *   this restore operation.
+     */
+    void restoreStarting(int numPackages);
+
+    /**
+     * An indication of which package is being restored currently, out of the
+     * total number provided in the restoreStarting() callback.  This method
+     * is not guaranteed to be called.
+     *
+     * @param nowBeingRestored The index, between 1 and the numPackages parameter
+     *   to the restoreStarting() callback, of the package now being restored.
+     */
+    void onUpdate(int nowBeingRestored);
+
+    /**
+     * The restore operation has completed.
+     *
+     * @param error Zero on success; a nonzero error code if the restore operation
+     *   as a whole failed.
+     */
+    void restoreFinished(int error);
+}
diff --git a/core/java/android/backup/IRestoreSession.aidl b/core/java/android/backup/IRestoreSession.aidl
index 6bca865..2a1fbc1 100644
--- a/core/java/android/backup/IRestoreSession.aidl
+++ b/core/java/android/backup/IRestoreSession.aidl
@@ -17,6 +17,7 @@
 package android.backup;
 
 import android.backup.RestoreSet;
+import android.backup.IRestoreObserver;
 
 /**
  * Binder interface used by clients who wish to manage a restore operation.  Every
@@ -41,8 +42,10 @@
      *
      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
      *   the restore set that should be used.
+     * @param observer If non-null, this binder points to an object that will receive
+     *   progress callbacks during the restore operation.
      */
-    int performRestore(int token);
+    int performRestore(long token, IRestoreObserver observer);
 
     /**
      * End this restore session.  After this method is called, the IRestoreSession binder
diff --git a/core/java/android/backup/RestoreSet.java b/core/java/android/backup/RestoreSet.java
index 96a99ae..eeca148 100644
--- a/core/java/android/backup/RestoreSet.java
+++ b/core/java/android/backup/RestoreSet.java
@@ -43,14 +43,14 @@
      * transport.  This is guaranteed to be valid for the duration of a restore
      * session, but is meaningless once the session has ended.
      */
-    public int token;
+    public long token;
 
 
     public RestoreSet() {
         // Leave everything zero / null
     }
 
-    public RestoreSet(String _name, String _dev, int _token) {
+    public RestoreSet(String _name, String _dev, long _token) {
         name = _name;
         device = _dev;
         token = _token;
@@ -65,7 +65,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(name);
         out.writeString(device);
-        out.writeInt(token);
+        out.writeLong(token);
     }
 
     public static final Parcelable.Creator<RestoreSet> CREATOR
@@ -82,6 +82,6 @@
     private RestoreSet(Parcel in) {
         name = in.readString();
         device = in.readString();
-        token = in.readInt();
+        token = in.readLong();
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java
index f492629..4a7b399 100644
--- a/core/java/android/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/backup/SharedPreferencesBackupHelper.java
@@ -30,7 +30,7 @@
     private Context mContext;
     private String[] mPrefGroups;
 
-    public SharedPreferencesBackupHelper(Context context, String[] prefGroups) {
+    public SharedPreferencesBackupHelper(Context context, String... prefGroups) {
         super(context);
 
         mContext = context;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 609fa74..6fe5506 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1578,6 +1578,16 @@
     public static final String ACTION_REBOOT =
             "android.intent.action.REBOOT";
 
+    /**
+     * @hide
+     * TODO: This will be unhidden in a later CL.
+     * Broadcast Action: The TextToSpeech synthesizer has completed processing 
+     * all of the text in the speech queue.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
+            "android.intent.action.TTS_QUEUE_PROCESSING_COMPLETED";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 85d877a..27783ef 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -235,6 +235,12 @@
     public static final int CONFIG_ORIENTATION = 0x0080;
     /**
      * Bit in {@link #configChanges} that indicates that the activity
+     * can itself handle changes to the screen layout.  Set from the
+     * {@link android.R.attr#configChanges} attribute.
+     */
+    public static final int CONFIG_SCREEN_LAYOUT = 0x0100;
+    /**
+     * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle changes to the font scaling factor.  Set from the
      * {@link android.R.attr#configChanges} attribute.  This is
      * not a core resource configutation, but a higher-level value, so its
@@ -248,8 +254,8 @@
      * Contains any combination of {@link #CONFIG_FONT_SCALE},
      * {@link #CONFIG_MCC}, {@link #CONFIG_MNC},
      * {@link #CONFIG_LOCALE}, {@link #CONFIG_TOUCHSCREEN},
-     * {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION}, and
-     * {@link #CONFIG_ORIENTATION}.  Set from the
+     * {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION},
+     * {@link #CONFIG_ORIENTATION}, and {@link #CONFIG_SCREEN_LAYOUT}.  Set from the
      * {@link android.R.attr#configChanges} attribute.
      */
     public int configChanges;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2a2cf93..bcf95b6 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -138,10 +138,27 @@
 
     /**
      * Value for {@link #flags}: true when the application's window can be
-     * expanded over default window size in target density (320x480 for
-     * 1.0 density, 480x720 for 1.5 density etc)
+     * reduced in size for smaller screens.  Corresponds to
+     * {@link android.R.styleable#AndroidManifestSupportsScreens_smallScreens
+     * android:smallScreens}.
      */
-    public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<9;
+    public static final int FLAG_SUPPORTS_SMALL_SCREENS = 1<<9;
+    
+    /**
+     * Value for {@link #flags}: true when the application's window can be
+     * displayed on normal screens.  Corresponds to
+     * {@link android.R.styleable#AndroidManifestSupportsScreens_normalScreens
+     * android:normalScreens}.
+     */
+    public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10; 
+    
+    /**
+     * Value for {@link #flags}: true when the application's window can be
+     * increased in size for larger screens.  Corresponds to
+     * {@link android.R.styleable#AndroidManifestSupportsScreens_largeScreens
+     * android:smallScreens}.
+     */
+    public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11;
     
     /**
      * Value for {@link #flags}: this is false if the application has set
@@ -149,7 +166,7 @@
      * 
      * {@hide}
      */
-    public static final int FLAG_ALLOW_BACKUP = 1<<10;
+    public static final int FLAG_ALLOW_BACKUP = 1<<12;
     
     /**
      * Indicates that the application supports any densities;
@@ -164,7 +181,9 @@
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
      * {@link #FLAG_ALLOW_TASK_REPARENTING}
      * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
-     * {@link #FLAG_TEST_ONLY}.
+     * {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS},
+     * {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
+     * {@link #FLAG_SUPPORTS_LARGE_SCREENS}.
      */
     public int flags = 0;
     
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab9518e..558b0c3 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -668,6 +668,11 @@
         }
         sa.recycle();
 
+        // Resource boolean are -1, so 1 means we don't know the value.
+        int supportsSmallScreens = 1;
+        int supportsNormalScreens = 1;
+        int supportsLargeScreens = 1;
+        
         int outerDepth = parser.getDepth();
         while ((type=parser.next()) != parser.END_DOCUMENT
                && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -876,8 +881,24 @@
 
                 XmlUtils.skipCurrentTag(parser);
 
-            } else if (tagName.equals("expandable")) {
-                pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+            } else if (tagName.equals("supports-screens")) {
+                sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.AndroidManifestSupportsScreens);
+
+                // This is a trick to get a boolean and still able to detect
+                // if a value was actually set.
+                supportsSmallScreens = sa.getInteger(
+                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
+                        supportsSmallScreens);
+                supportsNormalScreens = sa.getInteger(
+                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
+                        supportsNormalScreens);
+                supportsLargeScreens = sa.getInteger(
+                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
+                        supportsLargeScreens);
+
+                sa.recycle();
+                
                 XmlUtils.skipCurrentTag(parser);
             } else {
                 Log.w(TAG, "Bad element under <manifest>: "
@@ -910,7 +931,20 @@
             pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
             pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
         }
-        // TODO: enable all density & expandable if target sdk is higher than donut 
+        
+        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+                && pkg.applicationInfo.targetSdkVersion
+                        >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
+            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+        }
+        if (supportsNormalScreens != 0) {
+            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+        }
+        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+                && pkg.applicationInfo.targetSdkVersion
+                        >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
+            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+        }
         
         int size = pkg.supportsDensityList.size();
         if (size > 0) {
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 1c91736..5c7b01f 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -601,7 +601,7 @@
     public native final void setConfiguration(int mcc, int mnc, String locale,
             int orientation, int touchscreen, int density, int keyboard,
             int keyboardHidden, int navigation, int screenWidth, int screenHeight,
-            int majorVersion);
+            int screenLayout, int majorVersion);
 
     /**
      * Retrieve the resource identifier for the given resource name.
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 680fef8..4e6fe07 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -17,8 +17,15 @@
 package android.content.res;
 
 import android.content.pm.ApplicationInfo;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Region;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 
 /**
  * CompatibilityInfo class keeps the information about compatibility mode that the application is
@@ -27,6 +34,9 @@
  *  {@hide} 
  */
 public class CompatibilityInfo {
+    private static final boolean DBG = false;
+    private static final String TAG = "CompatibilityInfo";
+    
     /** default compatibility info object for compatible applications */
     public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo(); 
 
@@ -41,36 +51,81 @@
     public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
 
     /**
+     * The x-shift mode that controls the position of the content or the window under
+     * compatibility mode.
+     * {@see getTranslator}
+     * {@see Translator#mShiftMode}
+     */
+    private static final int X_SHIFT_NONE = 0;
+    private static final int X_SHIFT_CONTENT = 1;
+    private static final int X_SHIFT_AND_CLIP_CONTENT = 2;
+    private static final int X_SHIFT_WINDOW = 3;
+
+
+    /**
+     *  A compatibility flags
+     */
+    private int mCompatibilityFlags;
+    
+    /**
+     * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
+     * {@see compatibilityFlag}
+     */
+    private static final int SCALING_REQUIRED = 1; 
+
+    /**
+     * A flag mask to indicates that the application can expand over the original size.
+     * The flag is set to true if
+     * 1) Application declares its expandable in manifest file using <expandable /> or
+     * 2) The screen size is same as (320 x 480) * density. 
+     * {@see compatibilityFlag}
+     */
+    private static final int EXPANDABLE = 2;
+    
+    /**
+     * A flag mask to tell if the application is configured to be expandable. This differs
+     * from EXPANDABLE in that the application that is not expandable will be 
+     * marked as expandable if it runs in (320x 480) * density screen size.
+     */
+    private static final int CONFIGURED_EXPANDABLE = 4; 
+
+    private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE;
+
+    /**
      * Application's scale.
      */
-    public final float mApplicationScale;
+    public final float applicationScale;
 
     /**
      * Application's inverted scale.
      */
-    public final float mApplicationInvertedScale;
-    
-    /**
-     * A boolean flag to indicates that the application can expand over the original size.
-     * The flag is set to true if
-     * 1) Application declares its expandable in manifest file using <expandable /> or
-     * 2) The screen size is same as (320 x 480) * density. 
-     */
-    public boolean mExpandable;
+    public final float applicationInvertedScale;
 
     /**
-     * A expandable flag in the configuration.
+     * The flags from ApplicationInfo.
      */
-    public final boolean mConfiguredExpandable;
+    public final int appFlags;
     
     /**
-     * A boolean flag to tell if the application needs scaling (when mApplicationScale != 1.0f)
+     * Window size in Compatibility Mode, in real pixels. This is updated by
+     * {@link DisplayMetrics#updateMetrics}.
      */
-    public final boolean mScalingRequired;
+    private int mWidth;
+    private int mHeight;
+    
+    /**
+     * The x offset to center the window content. In X_SHIFT_WINDOW mode, the offset is added
+     * to the window's layout. In X_SHIFT_CONTENT/X_SHIFT_AND_CLIP_CONTENT mode, the offset
+     * is used to translate the Canvas.
+     */
+    private int mXOffset;
 
     public CompatibilityInfo(ApplicationInfo appInfo) {
-        mExpandable = mConfiguredExpandable =
-            (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0;
+        appFlags = appInfo.flags;
+        
+        if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+            mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
+        }
         
         float packageDensityScale = -1.0f;
         if (appInfo.supportsDensities != null) {
@@ -93,23 +148,326 @@
             }
         }
         if (packageDensityScale > 0.0f) {
-            mApplicationScale = packageDensityScale;
+            applicationScale = packageDensityScale;
         } else {
-            mApplicationScale = DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
+            applicationScale =
+                    DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
         }
-        mApplicationInvertedScale = 1.0f / mApplicationScale;
-        mScalingRequired = mApplicationScale != 1.0f;
+        applicationInvertedScale = 1.0f / applicationScale;
+        if (applicationScale != 1.0f) {
+            mCompatibilityFlags |= SCALING_REQUIRED;
+        }
     }
 
     private CompatibilityInfo() {
-        mApplicationScale = mApplicationInvertedScale = 1.0f;
-        mExpandable = mConfiguredExpandable = true;
-        mScalingRequired = false;
+        appFlags = ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+                | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
+                | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+        applicationScale = applicationInvertedScale = 1.0f;
+        mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
     }
 
+    /**
+     * Sets the application's visible rect in compatibility mode.
+     * @param xOffset the application's x offset that is added to center the content.
+     * @param widthPixels the application's width in real pixels on the screen.
+     * @param heightPixels the application's height in real pixels on the screen.
+     */
+    public void setVisibleRect(int xOffset, int widthPixels, int heightPixels) {
+        this.mXOffset = xOffset; 
+        mWidth = widthPixels;
+        mHeight = heightPixels;
+    }
+    
+    /**
+     * Sets expandable bit in the compatibility flag.
+     */
+    public void setExpandable(boolean expandable) {
+        if (expandable) {
+            mCompatibilityFlags |= CompatibilityInfo.EXPANDABLE;
+        } else {
+            mCompatibilityFlags &= ~CompatibilityInfo.EXPANDABLE;
+        }
+    }
+
+    /**
+     * @return true if the application is configured to be expandable.
+     */
+    public boolean isConfiguredExpandable() {
+        return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0;
+    }
+
+    /**
+     * @return true if the scaling is required
+     */
+    public boolean isScalingRequired() {
+        return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
+    }
+    
     @Override
     public String toString() {
-        return "CompatibilityInfo{scale=" + mApplicationScale +
-                ", expandable=" + mExpandable + "}"; 
+        return "CompatibilityInfo{scale=" + applicationScale +
+                ", compatibility flag=" + mCompatibilityFlags + "}"; 
     }
-}
+
+    /**
+     * Returns the translator which can translate the coordinates of the window.
+     * There are five different types of Translator.
+     * 
+     * 1) {@link CompatibilityInfo#X_SHIFT_AND_CLIP_CONTENT}
+     *   Shift and clip the content of the window at drawing time. Used for activities'
+     *   main window (with no gravity).
+     * 2) {@link CompatibilityInfo#X_SHIFT_CONTENT}
+     *   Shift the content of the window at drawing time. Used for windows that is created by
+     *   an application and expected to be aligned with the application window.
+     * 3) {@link CompatibilityInfo#X_SHIFT_WINDOW}
+     *   Create the window with adjusted x- coordinates. This is typically used 
+     *   in popup window, where it has to be placed relative to main window.
+     * 4) {@link CompatibilityInfo#X_SHIFT_NONE}
+     *   No adjustment required, such as dialog.
+     * 5) Same as X_SHIFT_WINDOW, but no scaling. This is used by {@link SurfaceView}, which
+     *  does not require scaling, but its window's location has to be adjusted.
+     * 
+     * @param params the window's parameter
+     */
+    public Translator getTranslator(WindowManager.LayoutParams params) {
+        if ( (mCompatibilityFlags & CompatibilityInfo.SCALING_EXPANDABLE_MASK)
+                == CompatibilityInfo.EXPANDABLE) {
+            if (DBG) Log.d(TAG, "no translation required");
+            return null;
+        }
+        
+        if ((mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) {
+            if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) {
+                if (DBG) Log.d(TAG, "translation for surface view selected");
+                return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f);
+            } else {
+                int shiftMode;
+                if (params.gravity == Gravity.NO_GRAVITY) {
+                    // For Regular Application window
+                    shiftMode = X_SHIFT_AND_CLIP_CONTENT;
+                    if (DBG) Log.d(TAG, "shift and clip translator");
+                } else if (params.width == WindowManager.LayoutParams.FILL_PARENT) {
+                    // For Regular Application window
+                    shiftMode = X_SHIFT_CONTENT;
+                    if (DBG) Log.d(TAG, "shift content translator");
+                } else if ((params.gravity & Gravity.LEFT) != 0 && params.x > 0) {
+                    shiftMode = X_SHIFT_WINDOW;
+                    if (DBG) Log.d(TAG, "shift window translator");
+                } else {
+                    shiftMode = X_SHIFT_NONE;
+                    if (DBG) Log.d(TAG, "no content/window translator");
+                }
+                return new Translator(shiftMode);
+            }
+        } else if (isScalingRequired()) {
+            return new Translator();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * A helper object to translate the screen and window coordinates back and forth.
+     * @hide
+     */
+    public class Translator {
+        final private int mShiftMode;
+        final public boolean scalingRequired;
+        final public float applicationScale;
+        final public float applicationInvertedScale;
+        
+        private Rect mContentInsetsBuffer = null;
+        private Rect mVisibleInsets = null;
+        
+        Translator(int shiftMode, boolean scalingRequired, float applicationScale,
+                float applicationInvertedScale) {
+            mShiftMode = shiftMode;
+            this.scalingRequired = scalingRequired;
+            this.applicationScale = applicationScale;
+            this.applicationInvertedScale = applicationInvertedScale;
+        }
+
+        Translator(int shiftMode) {
+            this(shiftMode,
+                    isScalingRequired(),
+                    CompatibilityInfo.this.applicationScale,
+                    CompatibilityInfo.this.applicationInvertedScale);
+        }
+        
+        Translator() {
+            this(X_SHIFT_NONE);
+        }
+
+        /**
+         * Translate the screen rect to the application frame.
+         */
+        public void translateRectInScreenToAppWinFrame(Rect rect) {
+            if (rect.isEmpty()) return; // skip if the window size is empty.
+            switch (mShiftMode) {
+                case X_SHIFT_AND_CLIP_CONTENT:
+                    rect.intersect(0, 0, mWidth, mHeight);
+                    break;
+                case X_SHIFT_CONTENT:
+                    rect.intersect(0, 0, mWidth + mXOffset, mHeight);
+                    break;
+                case X_SHIFT_WINDOW:
+                case X_SHIFT_NONE:
+                    break;
+            }
+            if (scalingRequired) {
+                rect.scale(applicationInvertedScale);
+            }
+        }
+
+        /**
+         * Translate the region in window to screen. 
+         */
+        public void translateRegionInWindowToScreen(Region transparentRegion) {
+            switch (mShiftMode) {
+                case X_SHIFT_AND_CLIP_CONTENT:
+                case X_SHIFT_CONTENT:
+                    transparentRegion.scale(applicationScale);
+                    transparentRegion.translate(mXOffset, 0);
+                    break;
+                case X_SHIFT_WINDOW:
+                case X_SHIFT_NONE:
+                    transparentRegion.scale(applicationScale);
+            }
+        }
+
+        /**
+         * Apply translation to the canvas that is necessary to draw the content.
+         */
+        public void translateCanvas(Canvas canvas) {
+            if (mShiftMode == X_SHIFT_CONTENT ||
+                    mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
+                // TODO: clear outside when rotation is changed.
+
+                // Translate x-offset only when the content is shifted.
+                canvas.translate(mXOffset, 0);
+            }
+            if (scalingRequired) {
+                canvas.scale(applicationScale, applicationScale);
+            }
+        }
+
+        /**
+         * Translate the motion event captured on screen to the application's window.
+         */
+        public void translateEventInScreenToAppWindow(MotionEvent event) {
+            if (mShiftMode == X_SHIFT_CONTENT ||
+                    mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
+                event.translate(-mXOffset, 0);
+            }
+            if (scalingRequired) {
+                event.scale(applicationInvertedScale);
+            }
+        }
+
+        /**
+         * Translate the window's layout parameter, from application's view to
+         * Screen's view.
+         */
+        public void translateWindowLayout(WindowManager.LayoutParams params) {
+            switch (mShiftMode) {
+                case X_SHIFT_NONE:
+                case X_SHIFT_AND_CLIP_CONTENT:
+                case X_SHIFT_CONTENT:
+                    params.scale(applicationScale);
+                    break;
+                case X_SHIFT_WINDOW:
+                    params.scale(applicationScale);
+                    params.x += mXOffset;
+                    break;
+            }
+        }
+        
+        /**
+         * Translate a Rect in application's window to screen.
+         */
+        public void translateRectInAppWindowToScreen(Rect rect) {
+            // TODO Auto-generated method stub
+            if (scalingRequired) {
+                rect.scale(applicationScale);
+            }
+            switch(mShiftMode) {
+                case X_SHIFT_NONE:
+                case X_SHIFT_WINDOW:
+                    break;
+                case X_SHIFT_CONTENT:
+                case X_SHIFT_AND_CLIP_CONTENT:
+                    rect.offset(mXOffset, 0);
+                    break;
+            }
+        }
+ 
+        /**
+         * Translate a Rect in screen coordinates into the app window's coordinates.
+         */
+        public void translateRectInScreenToAppWindow(Rect rect) {
+            switch (mShiftMode) {
+                case X_SHIFT_NONE:
+                case X_SHIFT_WINDOW:
+                    break;
+                case X_SHIFT_CONTENT: {
+                    rect.intersects(mXOffset, 0, rect.right, rect.bottom);
+                    int dx = Math.min(mXOffset, rect.left);
+                    rect.offset(-dx, 0);
+                    break;
+                }
+                case X_SHIFT_AND_CLIP_CONTENT: {
+                    rect.intersects(mXOffset, 0, mWidth + mXOffset, mHeight);
+                    int dx = Math.min(mXOffset, rect.left);
+                    rect.offset(-dx, 0);
+                    break;
+                }
+            }
+            if (scalingRequired) {
+                rect.scale(applicationInvertedScale);
+            }
+        }
+
+        /**
+         * Translate the location of the sub window.
+         * @param params
+         */
+        public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
+            if (scalingRequired) {
+                params.scale(applicationScale);
+            }
+            switch (mShiftMode) {
+                // the window location on these mode does not require adjustmenet.
+                case X_SHIFT_NONE:
+                case X_SHIFT_WINDOW:
+                    break;
+                case X_SHIFT_CONTENT:
+                case X_SHIFT_AND_CLIP_CONTENT:
+                    params.x += mXOffset;
+                    break;
+            }
+        }
+
+        /**
+         * Translate the content insets in application window to Screen. This uses
+         * the internal buffer for content insets to avoid extra object allocation.
+         */
+        public Rect getTranslatedContentInsets(Rect contentInsets) {
+            if (mContentInsetsBuffer == null) mContentInsetsBuffer = new Rect();
+            mContentInsetsBuffer.set(contentInsets);
+            translateRectInAppWindowToScreen(mContentInsetsBuffer);
+            return mContentInsetsBuffer;
+        }
+
+        /**
+         * Translate the visible insets in application window to Screen. This uses
+         * the internal buffer for content insets to avoid extra object allocation.
+         */
+        public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
+            if (mVisibleInsets == null) mVisibleInsets = new Rect();
+            mVisibleInsets.set(visibleInsets);
+            translateRectInAppWindowToScreen(mVisibleInsets);
+            return mVisibleInsets;
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index bb3486c..577aa60 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -116,6 +116,18 @@
      */
     public int orientation;
     
+    public static final int SCREENLAYOUT_UNDEFINED = 0;
+    public static final int SCREENLAYOUT_SMALL = 1;
+    public static final int SCREENLAYOUT_NORMAL = 2;
+    public static final int SCREENLAYOUT_LARGE = 3;
+    
+    /**
+     * Overall layout of the screen.  May be one of
+     * {@link #SCREENLAYOUT_SMALL}, {@link #SCREENLAYOUT_NORMAL},
+     * or {@link #SCREENLAYOUT_LARGE}.
+     */
+    public int screenLayout;
+    
     /**
      * Construct an invalid Configuration.  You must call {@link #setToDefaults}
      * for this object to be valid.  {@more}
@@ -141,6 +153,7 @@
         hardKeyboardHidden = o.hardKeyboardHidden;
         navigation = o.navigation;
         orientation = o.orientation;
+        screenLayout = o.screenLayout;
     }
 
     public String toString() {
@@ -165,6 +178,8 @@
         sb.append(navigation);
         sb.append(" orien=");
         sb.append(orientation);
+        sb.append(" layout=");
+        sb.append(screenLayout);
         sb.append('}');
         return sb.toString();
     }
@@ -183,6 +198,7 @@
         hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
         navigation = NAVIGATION_UNDEFINED;
         orientation = ORIENTATION_UNDEFINED;
+        screenLayout = SCREENLAYOUT_UNDEFINED;
     }
 
     /** {@hide} */
@@ -253,6 +269,11 @@
             changed |= ActivityInfo.CONFIG_ORIENTATION;
             orientation = delta.orientation;
         }
+        if (delta.screenLayout != SCREENLAYOUT_UNDEFINED
+                && screenLayout != delta.screenLayout) {
+            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
+            screenLayout = delta.screenLayout;
+        }
         
         return changed;
     }
@@ -276,9 +297,11 @@
      * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
      * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
      * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
-     * PackageManager.ActivityInfo.CONFIG_NAVIGATION}, or
+     * PackageManager.ActivityInfo.CONFIG_NAVIGATION},
      * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
-     * PackageManager.ActivityInfo.CONFIG_ORIENTATION}.
+     * PackageManager.ActivityInfo.CONFIG_ORIENTATION}, or
+     * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT
+     * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}.
      */
     public int diff(Configuration delta) {
         int changed = 0;
@@ -319,6 +342,10 @@
                 && orientation != delta.orientation) {
             changed |= ActivityInfo.CONFIG_ORIENTATION;
         }
+        if (delta.screenLayout != SCREENLAYOUT_UNDEFINED
+                && screenLayout != delta.screenLayout) {
+            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
+        }
         
         return changed;
     }
@@ -368,6 +395,7 @@
         dest.writeInt(hardKeyboardHidden);
         dest.writeInt(navigation);
         dest.writeInt(orientation);
+        dest.writeInt(screenLayout);
     }
 
     public static final Parcelable.Creator<Configuration> CREATOR
@@ -399,6 +427,7 @@
         hardKeyboardHidden = source.readInt();
         navigation = source.readInt();
         orientation = source.readInt();
+        screenLayout = source.readInt();
     }
 
     public int compareTo(Configuration that) {
@@ -428,6 +457,8 @@
         n = this.navigation - that.navigation;
         if (n != 0) return n;
         n = this.orientation - that.orientation;
+        if (n != 0) return n;
+        n = this.screenLayout - that.screenLayout;
         //if (n != 0) return n;
         return n;
     }
@@ -450,6 +481,6 @@
         return ((int)this.fontScale) + this.mcc + this.mnc
                 + this.locale.hashCode() + this.touchscreen
                 + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden
-                + this.navigation + this.orientation;
+                + this.navigation + this.orientation + this.screenLayout;
     }
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 71dbd38..d7512bb 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -158,10 +158,10 @@
         }
         updateConfiguration(config, metrics);
         assets.ensureStringBlocks();
-        if (!mCompatibilityInfo.mScalingRequired) {
-            mPreloadedDrawables = sPreloadedDrawables;
-        } else {
+        if (mCompatibilityInfo.isScalingRequired()) {
             mPreloadedDrawables = emptySparseArray();
+        } else {
+            mPreloadedDrawables = sPreloadedDrawables;
         }
     }
 
@@ -1267,7 +1267,8 @@
             }
             if (metrics != null) {
                 mMetrics.setTo(metrics);
-                mMetrics.updateMetrics(mCompatibilityInfo, mConfiguration.orientation);
+                mMetrics.updateMetrics(mCompatibilityInfo,
+                        mConfiguration.orientation, mConfiguration.screenLayout);
             }
             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
 
@@ -1299,7 +1300,7 @@
                     mConfiguration.touchscreen,
                     (int)(mMetrics.density*160), mConfiguration.keyboard,
                     keyboardHidden, mConfiguration.navigation, width, height,
-                    sSdkVersion);
+                    mConfiguration.screenLayout, sSdkVersion);
             int N = mDrawableCache.size();
             if (DEBUG_CONFIG) {
                 Log.d(TAG, "Cleaning up drawables config changes: 0x"
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index ca579b6..09fbc97 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -39,13 +39,16 @@
 public class Camera {
     private static final String TAG = "Camera";
     
-    // These match the enum in libs/android_runtime/android_hardware_Camera.cpp
-    private static final int SHUTTER_CALLBACK = 0;
-    private static final int RAW_PICTURE_CALLBACK = 1;
-    private static final int JPEG_PICTURE_CALLBACK = 2;
-    private static final int PREVIEW_CALLBACK = 3;
-    private static final int AUTOFOCUS_CALLBACK = 4;
-    private static final int ERROR_CALLBACK = 5;
+    // These match the enums in frameworks/base/include/ui/Camera.h
+    private static final int CAMERA_MSG_ERROR = 0;
+    private static final int CAMERA_MSG_SHUTTER = 1;
+    private static final int CAMERA_MSG_FOCUS = 2;
+    private static final int CAMERA_MSG_ZOOM = 3;
+    private static final int CAMERA_MSG_PREVIEW_FRAME = 4;
+    private static final int CAMERA_MSG_VIDEO_FRAME = 5;
+    private static final int CAMERA_MSG_POSTVIEW_FRAME = 6;
+    private static final int CAMERA_MSG_RAW_IMAGE = 7;
+    private static final int CAMERA_MSG_COMPRESSED_IMAGE = 8;
 
     private int mNativeContext; // accessed by native methods
     private EventHandler mEventHandler;
@@ -231,22 +234,23 @@
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
-            case SHUTTER_CALLBACK:
+            case CAMERA_MSG_SHUTTER:
                 if (mShutterCallback != null) {
                     mShutterCallback.onShutter();
                 }
                 return;
-            case RAW_PICTURE_CALLBACK:
+
+            case CAMERA_MSG_RAW_IMAGE:
                 if (mRawImageCallback != null)
                     mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
                 return;
 
-            case JPEG_PICTURE_CALLBACK:
+            case CAMERA_MSG_COMPRESSED_IMAGE:
                 if (mJpegCallback != null)
                     mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
                 return;
             
-            case PREVIEW_CALLBACK:
+            case CAMERA_MSG_PREVIEW_FRAME:
                 if (mPreviewCallback != null) {
                     mPreviewCallback.onPreviewFrame((byte[])msg.obj, mCamera);
                     if (mOneShot) {
@@ -255,12 +259,12 @@
                 }
                 return;
 
-            case AUTOFOCUS_CALLBACK:
+            case CAMERA_MSG_FOCUS:
                 if (mAutoFocusCallback != null)
                     mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
                 return;
 
-            case ERROR_CALLBACK:
+            case CAMERA_MSG_ERROR :
                 Log.e(TAG, "Error " + msg.arg1);
                 if (mErrorCallback != null)
                     mErrorCallback.onError(msg.arg1, mCamera);
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 6c13582..abfb274 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -127,12 +127,12 @@
 public abstract class AsyncTask<Params, Progress, Result> {
     private static final String LOG_TAG = "AsyncTask";
 
-    private static final int CORE_POOL_SIZE = 1;
-    private static final int MAXIMUM_POOL_SIZE = 10;
+    private static final int CORE_POOL_SIZE = 5;
+    private static final int MAXIMUM_POOL_SIZE = 128;
     private static final int KEEP_ALIVE = 10;
 
     private static final BlockingQueue<Runnable> sWorkQueue =
-            new LinkedBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE);
+            new LinkedBlockingQueue<Runnable>(10);
 
     private static final ThreadFactory sThreadFactory = new ThreadFactory() {
         private final AtomicInteger mCount = new AtomicInteger(1);
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8fcb4d7..d40ea6b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -21,6 +21,7 @@
 import android.util.Config;
 import android.util.Log;
 
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
@@ -378,6 +379,20 @@
     }
 
     /**
+     * Like startMethodTracing(String, int, int), but taking an already-opened
+     * FileDescriptor in which the trace is written.  The file name is also
+     * supplied simply for logging.  Makes a dup of the file descriptor.
+     * 
+     * Not exposed in the SDK unless we are really comfortable with supporting
+     * this and find it would be useful.
+     * @hide
+     */
+    public static void startMethodTracing(String traceName, FileDescriptor fd,
+        int bufferSize, int flags) {
+        VMDebug.startMethodTracing(traceName, fd, bufferSize, flags);
+    }
+
+    /**
      * Determine whether method tracing is currently active.
      * @hide
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 333c7cb1..1214abc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -573,7 +573,21 @@
      * directly to a gid.
      */
     public static final native int getGidForName(String name);
-    
+
+    /**
+     * Returns a uid for a currently running process.
+     * @param pid the process id
+     * @return the uid of the process, or -1 if the process is not running.
+     * @hide pending API council review
+     */
+    public static final int getUidForPid(int pid) {
+        String[] procStatusLabels = { "Uid:" };
+        long[] procStatusValues = new long[1];
+        procStatusValues[0] = -1;
+        Process.readProcLines("/proc/" + pid + "/status", procStatusLabels, procStatusValues);
+        return (int) procStatusValues[0];
+    }
+
     /**
      * Set the priority of a thread, based on Linux priorities.
      * 
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index 6ea2528..95e54324 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -150,7 +150,7 @@
 
         // Set the title bar if title is available, else no title bar
         final CharSequence title = getTitle();
-        Dialog dialog = mDialog = new Dialog(context, !TextUtils.isEmpty(title)
+        Dialog dialog = mDialog = new Dialog(context, TextUtils.isEmpty(title)
                 ? com.android.internal.R.style.Theme_NoTitleBar
                 : com.android.internal.R.style.Theme);
         dialog.setContentView(listView);
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 789fdff..1ba5e25e 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -91,6 +91,17 @@
      */
     public static final String EXTRA_APPEND_LOCATION = "com.android.browser.append_location";
 
+    /**
+     * The name of the extra data in the VIEW intent. The data is in the format of
+     * a byte array.
+     * <p>
+     * Any value sent here will be passed in the http request to the provided url as post data.
+     * <p>
+     * pending api approval
+     * @hide
+     */
+    public static final String EXTRA_POST_DATA = "com.android.browser.post_data";
+
     /* if you change column order you must also change indices
        below */
     public static final String[] HISTORY_PROJECTION = new String[] {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5dc03eb..7356326 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1274,6 +1274,50 @@
         public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
 
         /**
+         * CDMA only settings
+         * DTMF tone type played by the dialer when dialing.
+         *                 0 = Normal
+         *                 1 = Long
+         * @hide
+         */
+        public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
+
+        /**
+         * CDMA only settings
+         * Emergency Tone  0 = Off
+         *                 1 = Alert
+         *                 2 = Vibrate
+         * @hide
+         */
+        public static final String EMERGENCY_TONE = "emergency_tone";
+
+        /**
+         * CDMA only settings
+         * Whether the auto retry is enabled. The value is
+         * boolean (1 or 0).
+         * @hide
+         */
+        public static final String CALL_AUTO_RETRY = "call_auto_retry";
+
+        /**
+         * Whether the hearing aid is enabled. The value is
+         * boolean (1 or 0).
+         * @hide
+         */
+        public static final String HEARING_AID = "hearing_aid";
+
+        /**
+         * CDMA only settings
+         * TTY Mode
+         * 0 = OFF
+         * 1 = FULL
+         * 2 = VCO
+         * 3 = HCO
+         * @hide
+         */
+        public static final String TTY_MODE = "tty_mode";
+
+        /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index a27667b..c7cc8ed 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -57,6 +57,11 @@
     private SearchableInfo mDefaultSearchable = null;
     private SearchableInfo mDefaultSearchableForWebSearch = null;
 
+    public static String GOOGLE_SEARCH_COMPONENT_NAME =
+            "com.android.googlesearch/.GoogleSearch";
+    public static String ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME =
+            "com.google.android.providers.enhancedgooglesearch/.Launcher";
+
     /**
      *
      * @param context Context to use for looking up activities etc.
@@ -341,6 +346,18 @@
                     return component;
                 }
             }
+        } else {
+            // If the current preferred activity is GoogleSearch, and we detect
+            // EnhancedGoogleSearch installed as well, set the latter as preferred since that
+            // is a superset and provides more functionality.
+            ComponentName cn = new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
+            if (cn.flattenToShortString().equals(GOOGLE_SEARCH_COMPONENT_NAME)) {
+                ComponentName enhancedGoogleSearch = ComponentName.unflattenFromString(
+                        ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME);
+                if (setPreferredActivity(enhancedGoogleSearch, Intent.ACTION_WEB_SEARCH)) {
+                    return enhancedGoogleSearch;
+                }
+            }
         }
 
         if (ri == null) return null;
diff --git a/core/java/android/speech/tts/ITts.aidl b/core/java/android/speech/tts/ITts.aidl
index 02211fd4..47976e5 100755
--- a/core/java/android/speech/tts/ITts.aidl
+++ b/core/java/android/speech/tts/ITts.aidl
@@ -29,8 +29,12 @@
 interface ITts {

     void setSpeechRate(in int speechRate);

 

+    void setPitch(in int pitch);

+

     void speak(in String text, in int queueMode, in String[] params);

 

+    void speakIpa(in String ipaText, in int queueMode, in String[] params);

+

     boolean isSpeaking();

 

     void stop();

@@ -41,7 +45,9 @@
 

     void setLanguage(in String language, in String country, in String variant);

 

-    boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);

+    boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);
+

+    boolean synthesizeIpaToFile(in String ipaText, in String[] params, in String outputDirectory);

 

     void playEarcon(in String earcon, in int queueMode, in String[] params);

 

diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 9fc143d..8fa06fa 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -46,10 +46,6 @@
      * Denotes a generic operation failure.
      */
     public static final int TTS_ERROR                  = -1;
-    /**
-     * Denotes a failure due to a missing resource.
-     */
-    public static final int TTS_ERROR_MISSING_RESOURCE = -2;
 
     /**
      * Queue mode where all entries in the playback queue (media to be played
@@ -61,6 +57,37 @@
      */
     public static final int TTS_QUEUE_ADD = 1;
 
+
+    /**
+     * Denotes the language is available exactly as specified by the locale
+     */
+    public static final int TTS_LANG_COUNTRY_VAR_AVAILABLE = 2;
+
+
+    /**
+     * Denotes the language is available for the language and country specified 
+     * by the locale, but not the variant.
+     */
+    public static final int TTS_LANG_COUNTRY_AVAILABLE = 1;
+
+
+    /**
+     * Denotes the language is available for the language by the locale, 
+     * but not the country and variant.
+     */
+    public static final int TTS_LANG_AVAILABLE = 0;
+
+    /**
+     * Denotes the language data is missing.
+     */
+    public static final int TTS_LANG_MISSING_DATA = -1;
+
+    /**
+     * Denotes the language is not supported by the current TTS engine.
+     */
+    public static final int TTS_LANG_NOT_SUPPORTED = -2;
+
+
     /**
      * Called when the TTS has initialized.
      *
@@ -72,15 +99,6 @@
     }
 
     /**
-     * Called when the TTS has finished speaking by itself (speaking
-     * finished without being canceled).
-     *
-     */
-    public interface OnSpeechCompletedListener {
-        public void onSpeechCompleted();
-    }
-
-    /**
      * Internal constants for the TTS functionality
      *
      * {@hide}
@@ -100,6 +118,16 @@
         public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
         public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
         public static final int CHECK_VOICE_DATA_MISSING_DATA_NO_SDCARD = -3;
+        
+        // keys for the parameters passed with speak commands
+        public static final String TTS_KEY_PARAM_RATE = "rate";
+        public static final String TTS_KEY_PARAM_LANGUAGE = "language";
+        public static final String TTS_KEY_PARAM_COUNTRY = "country";
+        public static final String TTS_KEY_PARAM_VARIANT = "variant";
+        public static final int TTS_PARAM_POSITION_RATE = 0;
+        public static final int TTS_PARAM_POSITION_LANGUAGE = 2;
+        public static final int TTS_PARAM_POSITION_COUNTRY = 4;
+        public static final int TTS_PARAM_POSITION_VARIANT = 6;
     }
 
     /**
@@ -112,11 +140,11 @@
     private OnInitListener mInitListener = null;
     private boolean mStarted = false;
     private final Object mStartLock = new Object();
-    private ITtsCallback mITtsCallback;
-    private OnSpeechCompletedListener mSpeechCompListener = null;
-    private final Object mSpeechCompListenerLock = new Object();
-
-
+    private int mCachedRate = Engine.FALLBACK_TTS_DEFAULT_RATE;
+    private String mCachedLang = Engine.FALLBACK_TTS_DEFAULT_LANG;
+    private String mCachedCountry = Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
+    private String mCachedVariant = Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+    private String[] mCachedParams;
 
     /**
      * The constructor for the TTS.
@@ -130,24 +158,23 @@
     public TextToSpeech(Context context, OnInitListener listener) {
         mContext = context;
         mInitListener = listener;
+
+        mCachedParams = new String[2*4]; //4 parameters, store key and value
+        mCachedParams[Engine.TTS_PARAM_POSITION_RATE] = Engine.TTS_KEY_PARAM_RATE;
+        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE] = Engine.TTS_KEY_PARAM_LANGUAGE;
+        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY] = Engine.TTS_KEY_PARAM_COUNTRY;
+        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT] = Engine.TTS_KEY_PARAM_VARIANT;
+        updateCachedParamArray();
+
         initTts();
     }
 
 
-    public void setOnSpeechCompletedListener(final OnSpeechCompletedListener listener) {
-        synchronized(mSpeechCompListenerLock) {
-            mSpeechCompListener = listener;
-        }
-    }
-
-
-    private boolean dataFilesCheck() {
-        // TODO #TTS# config manager will be in settings
-        Log.i("TTS_FIXME", "FIXME in Tts: config manager will be in settings");
-        // TODO #TTS# implement checking of the correct installation of
-        //             the data files.
-
-        return true;
+    private void updateCachedParamArray() {
+        mCachedParams[Engine.TTS_PARAM_POSITION_RATE+1] = String.valueOf(mCachedRate);
+        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE+1] = mCachedLang;
+        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY+1] = mCachedCountry;
+        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT+1] = mCachedVariant;
     }
 
 
@@ -159,34 +186,7 @@
             public void onServiceConnected(ComponentName name, IBinder service) {
                 synchronized(mStartLock) {
                     mITts = ITts.Stub.asInterface(service);
-                    try {
-                        mITtsCallback = new ITtsCallback.Stub() {
-                            public void markReached(String mark)
-                            throws RemoteException {
-                                // call the listener of that event, but not
-                                // while locked.
-                                OnSpeechCompletedListener listener = null;
-                                synchronized(mSpeechCompListenerLock) {
-                                    listener = mSpeechCompListener;
-                                }
-                                if (listener != null) {
-                                    listener.onSpeechCompleted();
-                                }
-                            }
-                        };
-                        mITts.registerCallback(mITtsCallback);
-
-                    } catch (RemoteException e) {
-                        initTts();
-                        return;
-                    }
-
                     mStarted = true;
-                    // The callback can become null if the Android OS decides to
-                    // restart the TTS process as well as whatever is using it.
-                    // In such cases, do nothing - the error handling from the
-                    // speaking calls will kick in and force a proper restart of
-                    // the TTS.
                     if (mInitListener != null) {
                         // TODO manage failures and missing resources
                         mInitListener.onInit(TTS_SUCCESS);
@@ -333,8 +333,50 @@
                 return;
             }
             try {
-                // TODO support extra parameters, passing null for the moment
-                mITts.speak(text, queueMode, null);
+                // TODO support extra parameters, passing cache of current parameters for the moment
+                mITts.speak(text, queueMode, mCachedParams);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Speaks the IPA string using the specified queuing strategy and speech
+     * parameters. Note that the speech parameters are not universally supported
+     * by all engines and will be treated as a hint. The TTS library will try to
+     * fulfill these parameters as much as possible, but there is no guarantee
+     * that the voice used will have the properties specified.
+     *
+     * @param ipaText
+     *            The string of IPA text to be spoken.
+     * @param queueMode
+     *            The queuing strategy to use.
+     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
+     * @param params
+     *            The hashmap of speech parameters to be used.
+     */
+    public void speakIpa(String ipaText, int queueMode, HashMap<String,String> params)
+    {
+        synchronized (mStartLock) {
+            Log.i("TTS received: ", ipaText);
+            if (!mStarted) {
+                return;
+            }
+            try {
+                // TODO support extra parameters, passing cache of current parameters for the moment
+                mITts.speakIpa(ipaText, queueMode, mCachedParams);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -389,7 +431,27 @@
 
 
     public void playSilence(long durationInMs, int queueMode) {
-        // TODO implement, already present in TTS service
+        synchronized (mStartLock) {
+            if (!mStarted) {
+                return;
+            }
+            try {
+                // TODO support extra parameters, passing cache of current parameters for the moment
+                mITts.playSilence(durationInMs, queueMode, mCachedParams);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            }
+        }
     }
 
 
@@ -450,7 +512,6 @@
     }
 
 
-
     /**
      * Sets the speech rate for the TTS engine.
      *
@@ -471,7 +532,40 @@
             }
             try {
                 if (speechRate > 0) {
-                    mITts.setSpeechRate((int)(speechRate*100));
+                    mCachedRate = (int)(speechRate*100);
+                    updateCachedParamArray();
+                    mITts.setSpeechRate(mCachedRate);
+                }
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Sets the speech pitch for the TTS engine.
+     *
+     * Note that the pitch is not universally supported by all engines and
+     * will be treated as a hint. The TTS library will try to use the specified
+     * pitch, but there is no guarantee.
+     * This has no effect on any pre-recorded speech.
+     *
+     * @param pitch
+     *            The pitch for the TTS engine. 1 is the normal pitch,
+     *            lower values lower the tone of the synthesized voice,
+     *            greater values increase it.
+     */
+    public void setPitch(float pitch) {
+        synchronized (mStartLock) {
+            if (!mStarted) {
+                return;
+            }
+            try {
+                if (pitch > 0) {
+                    mITts.setPitch((int)(pitch*100));
                 }
             } catch (RemoteException e) {
                 // TTS died; restart it.
@@ -498,7 +592,11 @@
                 return;
             }
             try {
-                mITts.setLanguage(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant());
+                mCachedLang = loc.getISO3Language();
+                mCachedCountry = loc.getISO3Country();
+                mCachedVariant = loc.getVariant();
+                updateCachedParamArray();
+                mITts.setLanguage(mCachedLang, mCachedCountry, mCachedVariant);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -507,9 +605,23 @@
         }
     }
 
+    /**
+     * Checks if the specified language as represented by the locale is available.
+     *
+     * @param loc
+     *            The locale describing the language to be used.
+     * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
+               TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE.
+     */
+    public int isLanguageAvailable(Locale loc) {
+        //TODO: Implement isLanguageAvailable
+        return TTS_LANG_NOT_SUPPORTED;
+    }
+
+
 
     /**
-     * Speaks the given text using the specified queueing mode and parameters.
+     * Synthesizes the given text to a file using the specified parameters.
      *
      * @param text
      *            The String of text that should be synthesized
@@ -546,5 +658,42 @@
         }
     }
 
+    /**
+     * Synthesizes the given IPA text to a file using the specified parameters.
+     *
+     * @param text
+     *            The String of text that should be synthesized
+     * @param params
+     *            A hashmap of parameters.
+     * @param filename
+     *            The string that gives the full output filename; it should be
+     *            something like "/sdcard/myappsounds/mysound.wav".
+     * @return A boolean that indicates if the synthesis succeeded
+     */
+    public boolean synthesizeIpaToFile(String ipaText,
+            HashMap<String,String> params, String filename) {
+        synchronized (mStartLock) {
+            if (!mStarted) {
+                return false;
+            }
+            try {
+                // TODO support extra parameters, passing null for the moment
+                return mITts.synthesizeIpaToFile(ipaText, null, filename);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                mStarted = false;
+                initTts();
+            }
+            return false;
+        }
+    }
 
 }
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index a095913..4179edb 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -103,11 +103,60 @@
 
     /**
      * Update the display metrics based on the compatibility info and orientation
+     * NOTE: DO NOT EXPOSE THIS API!  It is introducing a circular dependency
+     * with the higher-level android.res package.
      * {@hide}
      */
-    public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation) {
-        if (compatibilityInfo.mScalingRequired) {
-            float invertedRatio = compatibilityInfo.mApplicationInvertedScale;
+    public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation,
+            int screenLayout) {
+        int xOffset = 0;
+        if (!compatibilityInfo.isConfiguredExpandable()) {
+            // Note: this assume that configuration is updated before calling
+            // updateMetrics method.
+            if (screenLayout == Configuration.SCREENLAYOUT_LARGE) {
+                // This is a large screen device and the app is not 
+                // compatible with large screens, to diddle it.
+                
+                compatibilityInfo.setExpandable(false);
+                // Figure out the compatibility width and height of the screen.
+                int defaultWidth;
+                int defaultHeight;
+                switch (orientation) {
+                    case Configuration.ORIENTATION_LANDSCAPE: {
+                        defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
+                        defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
+                        break;
+                    }
+                    case Configuration.ORIENTATION_PORTRAIT:
+                    case Configuration.ORIENTATION_SQUARE:
+                    default: {
+                        defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
+                        defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
+                        break;
+                    }
+                    case Configuration.ORIENTATION_UNDEFINED: {
+                        // don't change
+                        return;
+                    }
+                }
+                
+                if (defaultWidth < widthPixels) {
+                    // content/window's x offset in original pixels
+                    xOffset = ((widthPixels - defaultWidth) / 2);
+                    widthPixels = defaultWidth;
+                }
+                if (defaultHeight < heightPixels) {
+                    heightPixels = defaultHeight;
+                }
+                
+            } else {
+                // the screen size is same as expected size. make it expandable
+                compatibilityInfo.setExpandable(true);
+            }
+        }
+        compatibilityInfo.setVisibleRect(xOffset, widthPixels, heightPixels);
+        if (compatibilityInfo.isScalingRequired()) {
+            float invertedRatio = compatibilityInfo.applicationInvertedScale;
             density *= invertedRatio;
             scaledDensity *= invertedRatio;
             xdpi *= invertedRatio;
@@ -115,46 +164,9 @@
             widthPixels *= invertedRatio;
             heightPixels *= invertedRatio;
         }
-        if (!compatibilityInfo.mConfiguredExpandable) {
-            // Note: this assume that configuration is updated before calling
-            // updateMetrics method.
-            int defaultWidth;
-            int defaultHeight;
-            switch (orientation) {
-                case Configuration.ORIENTATION_LANDSCAPE: {
-                    defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
-                    defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
-                    break;
-                }
-                case Configuration.ORIENTATION_PORTRAIT:
-                case Configuration.ORIENTATION_SQUARE:
-                default: {
-                    defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
-                    defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
-                    break;
-                }
-                case Configuration.ORIENTATION_UNDEFINED: {
-                    // don't change
-                    return;
-                }
-            }
-            
-            if (defaultWidth == widthPixels && defaultHeight == heightPixels) {
-                // the screen size is same as expected size. make it expandable
-                compatibilityInfo.mExpandable = true;
-            } else {
-                compatibilityInfo.mExpandable = false;
-                // adjust the size only when the device's screen is bigger.
-                if (defaultWidth < widthPixels) {
-                    widthPixels = defaultWidth;
-                }
-                if (defaultHeight < heightPixels) {
-                    heightPixels = defaultHeight;
-                }
-            }
-        }
     }
 
+    @Override
     public String toString() {
         return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
             ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ca01448..a224ed3 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -212,28 +212,47 @@
     }
 
     /**
-     * Scales down the cood of this event by the given scale.
+     * Scales down the coordination of this event by the given scale.
      *
      * @hide
      */
     public void scale(float scale) {
-        if (scale != 1.0f) {
-            mX *= scale;
-            mY *= scale;
-            mRawX *= scale;
-            mRawY *= scale;
-            mSize *= scale;
-            mXPrecision *= scale;
-            mYPrecision *= scale;
-            if (mHistory != null) {
-                float[] history = mHistory;
-                int length = history.length;
-                for (int i = 0; i < length; i += 4) {
-                    history[i] *= scale;        // X
-                                                // history[i + 2] == pressure
-                    history[i + 1] *= scale;    // Y
-                    history[i + 3] *= scale;    // Size, TODO: square this?
-                }
+        mX *= scale;
+        mY *= scale;
+        mRawX *= scale;
+        mRawY *= scale;
+        mSize *= scale;
+        mXPrecision *= scale;
+        mYPrecision *= scale;
+        if (mHistory != null) {
+            float[] history = mHistory;
+            int length = history.length;
+            for (int i = 0; i < length; i += 4) {
+                history[i] *= scale;        // X
+                history[i + 1] *= scale;    // Y
+                // no need to scale pressure ([i+2])
+                history[i + 3] *= scale;    // Size, TODO: square this?
+            }
+        }
+    }
+
+    /**
+     * Translate the coordination of the event by given x and y.
+     *
+     * @hide
+     */
+    public void translate(float dx, float dy) {
+        mX += dx;
+        mY += dy;
+        mRawX += dx;
+        mRawY += dx;
+        if (mHistory != null) {
+            float[] history = mHistory;
+            int length = history.length;
+            for (int i = 0; i < length; i += 4) {
+                history[i] += dx;        // X
+                history[i + 1] += dy;    // Y
+                // no need to translate pressure (i+2) and size (i+3) 
             }
         }
     }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 082cca2..45b0f0a7 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
+import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
@@ -138,24 +139,21 @@
     int mFormat = -1;
     int mType = -1;
     final Rect mSurfaceFrame = new Rect();
-    private final CompatibilityInfo mCompatibilityInfo;
+    private Translator mTranslator;
 
     public SurfaceView(Context context) {
         super(context);
         setWillNotDraw(true);
-        mCompatibilityInfo = context.getResources().getCompatibilityInfo();
     }
     
     public SurfaceView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setWillNotDraw(true);
-        mCompatibilityInfo = context.getResources().getCompatibilityInfo();
     }
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         setWillNotDraw(true);
-        mCompatibilityInfo = context.getResources().getCompatibilityInfo();
     }
     
     /**
@@ -258,9 +256,9 @@
     public boolean dispatchTouchEvent(MotionEvent event) {
         // SurfaceView uses pre-scaled size unless fixed size is requested. This hook
         // scales the event back to the pre-scaled coordinates for such surface.
-        if (mRequestedWidth < 0 && mCompatibilityInfo.mScalingRequired) {
+        if (mRequestedWidth < 0 && mTranslator != null) {
             MotionEvent scaledBack = MotionEvent.obtain(event);
-            scaledBack.scale(mCompatibilityInfo.mApplicationScale);
+            scaledBack.scale(mTranslator.applicationScale);
             try {
                 return super.dispatchTouchEvent(scaledBack);
             } finally {
@@ -297,15 +295,18 @@
         if (!mHaveFrame) {
             return;
         }
-        float appScale = mCompatibilityInfo.mApplicationScale;
+        mTranslator = ((ViewRoot)getRootView().getParent()).mTranslator;
+
+        float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
         
         int myWidth = mRequestedWidth;
         if (myWidth <= 0) myWidth = getWidth();
         int myHeight = mRequestedHeight;
         if (myHeight <= 0) myHeight = getHeight();
 
-        // Use original size for surface unless fixed size is requested.
-        if (mRequestedWidth <= 0 && mCompatibilityInfo.mScalingRequired) {
+        // Use original size if the app specified the size of the view,
+        // and let the flinger to scale up.
+        if (mRequestedWidth <= 0 && mTranslator != null && mTranslator.scalingRequired) {
             myWidth *= appScale;
             myHeight *= appScale;
         }
@@ -325,7 +326,7 @@
                     + " visible=" + visibleChanged
                     + " left=" + (mLeft != mLocation[0])
                     + " top=" + (mTop != mLocation[1]));
-            
+
             try {
                 final boolean visible = mVisible = mRequestedVisible;
                 mLeft = mLocation[0];
@@ -335,16 +336,23 @@
                 mFormat = mRequestedFormat;
                 mType = mRequestedType;
 
-                // Scaling window's layout here because mLayout is not used elsewhere.
-                mLayout.x = (int) (mLeft * appScale);
-                mLayout.y = (int) (mTop * appScale);
-                mLayout.width = (int) (getWidth() * appScale);
-                mLayout.height = (int) (getHeight() * appScale);
+                // Scaling/Translate window's layout here because mLayout is not used elsewhere.
+                
+                // Places the window relative
+                mLayout.x = mLeft;
+                mLayout.y = mTop;
+                mLayout.width = getWidth();
+                mLayout.height = getHeight();
+                if (mTranslator != null) {
+                    mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
+                }
+                
                 mLayout.format = mRequestedFormat;
                 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                               | WindowManager.LayoutParams.FLAG_SCALED
                               | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                               | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                              | WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING
                               ;
 
                 mLayout.memoryType = mRequestedType;
@@ -371,13 +379,6 @@
                         visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
                         mVisibleInsets, mSurface);
 
-                if (mCompatibilityInfo.mScalingRequired) {
-                    float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
-                    mContentInsets.scale(invertedScale);
-                    mVisibleInsets.scale(invertedScale);
-                    mWinFrame.scale(invertedScale);
-                }
-
                 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
                         + ", vis=" + visible + ", frame=" + mWinFrame);
                 mSurfaceFrame.left = 0;
@@ -446,24 +447,14 @@
 
     private static class MyWindow extends IWindow.Stub {
         private final WeakReference<SurfaceView> mSurfaceView;
-        private final CompatibilityInfo mCompatibilityInfo;
 
         public MyWindow(SurfaceView surfaceView) {
             mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
-            mCompatibilityInfo = surfaceView.getContext().getResources().getCompatibilityInfo();
         }
 
         public void resized(int w, int h, Rect coveredInsets,
                 Rect visibleInsets, boolean reportDraw) {
             SurfaceView surfaceView = mSurfaceView.get();
-            if (mCompatibilityInfo.mScalingRequired) {
-                float scale = mCompatibilityInfo.mApplicationInvertedScale;
-                w *= scale;
-                h *= scale;
-                coveredInsets.scale(scale);
-                visibleInsets.scale(scale);
-            }
-
             if (surfaceView != null) {
                 if (localLOGV) Log.v(
                         "SurfaceView", surfaceView + " got resized: w=" +
@@ -626,9 +617,6 @@
             Canvas c = null;
             if (!mDrawingStopped && mWindow != null) {
                 Rect frame = dirty != null ? dirty : mSurfaceFrame;
-                if (mCompatibilityInfo.mScalingRequired) {
-                    frame.scale(mCompatibilityInfo.mApplicationScale);
-                }
                 try {
                     c = mSurface.lockCanvas(frame);
                 } catch (Exception e) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f17f0e4..b3180ca 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1690,6 +1690,7 @@
     private int[] mDrawableState = null;
 
     private SoftReference<Bitmap> mDrawingCache;
+    private SoftReference<Bitmap> mUnscaledDrawingCache;
 
     /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
@@ -5783,28 +5784,52 @@
     }
 
     /**
+     * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
+     * 
+     * @return A non-scaled bitmap representing this view or null if cache is disabled.
+     * 
+     * @see #getDrawingCache(boolean)
+     */
+    public Bitmap getDrawingCache() {
+        return getDrawingCache(false);
+    }
+
+    /**
      * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap
      * is null when caching is disabled. If caching is enabled and the cache is not ready,
      * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not
      * draw from the cache when the cache is enabled. To benefit from the cache, you must
      * request the drawing cache by calling this method and draw it on screen if the
      * returned bitmap is not null.</p>
+     * 
+     * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,
+     * this method will create a bitmap of the same size as this view. Because this bitmap
+     * will be drawn scaled by the parent ViewGroup, the result on screen might show
+     * scaling artifacts. To avoid such artifacts, you should call this method by setting
+     * the auto scaling to true. Doing so, however, will generate a bitmap of a different
+     * size than the view. This implies that your application must be able to handle this
+     * size.</p>
+     * 
+     * @param autoScale Indicates whether the generated bitmap should be scaled based on
+     *        the current density of the screen when the application is in compatibility
+     *        mode.
      *
-     * @return a bitmap representing this view or null if cache is disabled
-     *
+     * @return A bitmap representing this view or null if cache is disabled.
+     * 
      * @see #setDrawingCacheEnabled(boolean)
      * @see #isDrawingCacheEnabled()
-     * @see #buildDrawingCache()
+     * @see #buildDrawingCache(boolean)
      * @see #destroyDrawingCache()
      */
-    public Bitmap getDrawingCache() {
+    public Bitmap getDrawingCache(boolean autoScale) {
         if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
             return null;
         }
         if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
-            buildDrawingCache();
+            buildDrawingCache(autoScale);
         }
-        return mDrawingCache == null ? null : mDrawingCache.get();
+        return autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
+                (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
     }
 
     /**
@@ -5823,6 +5848,11 @@
             if (bitmap != null) bitmap.recycle();
             mDrawingCache = null;
         }
+        if (mUnscaledDrawingCache != null) {
+            final Bitmap bitmap = mUnscaledDrawingCache.get();
+            if (bitmap != null) bitmap.recycle();
+            mUnscaledDrawingCache = null;
+        }
     }
 
     /**
@@ -5850,18 +5880,36 @@
     }
 
     /**
+     * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p>
+     * 
+     * @see #buildDrawingCache(boolean)
+     */
+    public void buildDrawingCache() {
+        buildDrawingCache(false);
+    }
+
+    /**
      * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p>
      *
      * <p>If you call {@link #buildDrawingCache()} manually without calling
      * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
      * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p>
+     * 
+     * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,
+     * this method will create a bitmap of the same size as this view. Because this bitmap
+     * will be drawn scaled by the parent ViewGroup, the result on screen might show
+     * scaling artifacts. To avoid such artifacts, you should call this method by setting
+     * the auto scaling to true. Doing so, however, will generate a bitmap of a different
+     * size than the view. This implies that your application must be able to handle this
+     * size.</p>
      *
      * @see #getDrawingCache()
      * @see #destroyDrawingCache()
      */
-    public void buildDrawingCache() {
-        if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null ||
-                mDrawingCache.get() == null) {
+    public void buildDrawingCache(boolean autoScale) {
+        if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
+                (mDrawingCache == null || mDrawingCache.get() == null) :
+                (mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) {
 
             if (ViewDebug.TRACE_HIERARCHY) {
                 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
@@ -5874,12 +5922,11 @@
             int height = mBottom - mTop;
 
             final AttachInfo attachInfo = mAttachInfo;
-            if (attachInfo != null) {
-                final boolean scalingRequired = attachInfo.mScalingRequired;
-                if (scalingRequired) {
-                    width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
-                    height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
-                }
+            final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
+
+            if (autoScale && scalingRequired) {
+                width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
+                height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
             }
 
             final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
@@ -5894,7 +5941,8 @@
             }
 
             boolean clear = true;
-            Bitmap bitmap = mDrawingCache == null ? null : mDrawingCache.get();
+            Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
+                    (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
 
             if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
 
@@ -5923,12 +5971,20 @@
 
                 try {
                     bitmap = Bitmap.createBitmap(width, height, quality);
-                    mDrawingCache = new SoftReference<Bitmap>(bitmap);
+                    if (autoScale) {
+                        mDrawingCache = new SoftReference<Bitmap>(bitmap);
+                    } else {
+                        mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap);
+                    }
                 } catch (OutOfMemoryError e) {
                     // If there is not enough memory to create the bitmap cache, just
                     // ignore the issue as bitmap caches are not required to draw the
                     // view hierarchy
-                    mDrawingCache = null;
+                    if (autoScale) {
+                        mDrawingCache = null;
+                    } else {
+                        mUnscaledDrawingCache = null;
+                    }
                     return;
                 }
 
@@ -5940,13 +5996,6 @@
                 canvas = attachInfo.mCanvas;
                 if (canvas == null) {
                     canvas = new Canvas();
-
-                    // NOTE: This should have to happen only once since compatibility
-                    //       mode should not change at runtime
-                    if (attachInfo.mScalingRequired) {
-                        final float scale = attachInfo.mApplicationScale;
-                        canvas.scale(scale, scale);
-                    }
                 }
                 canvas.setBitmap(bitmap);
                 // Temporarily clobber the cached Canvas in case one of our children
@@ -5965,6 +6014,12 @@
 
             computeScroll();
             final int restoreCount = canvas.save();
+            
+            if (autoScale && scalingRequired) {
+                final float scale = attachInfo.mApplicationScale;
+                canvas.scale(scale, scale);
+            }
+            
             canvas.translate(-mScrollX, -mScrollY);
 
             mPrivateFlags |= DRAWN;
@@ -6543,7 +6598,7 @@
         boolean changed = false;
 
         if (DBG) {
-            System.out.println(this + " View.setFrame(" + left + "," + top + ","
+            Log.d("View", this + " View.setFrame(" + left + "," + top + ","
                     + right + "," + bottom + ")");
         }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f803b5a..f7b7f02 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1166,7 +1166,7 @@
                 final View child = children[i];
                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                     child.setDrawingCacheEnabled(true);
-                    child.buildDrawingCache();
+                    child.buildDrawingCache(true);
                 }
             }
 
@@ -1208,7 +1208,7 @@
                     bindLayoutAnimation(child);
                     if (cache) {
                         child.setDrawingCacheEnabled(true);
-                        child.buildDrawingCache();
+                        child.buildDrawingCache(true);
                     }
                 }
             }
@@ -1448,7 +1448,7 @@
         Bitmap cache = null;
         if ((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();
+            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 d35b048..65457c5 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -128,13 +128,12 @@
     Rect mDirty; // will be a graphics.Region soon
     boolean mIsAnimating;
 
-    private CompatibilityInfo mCompatibilityInfo;
+    CompatibilityInfo.Translator mTranslator;
 
     final View.AttachInfo mAttachInfo;
 
     final Rect mTempRect; // used in the transaction to not thrash the heap.
     final Rect mVisRect; // used to retrieve visible rect of focused view.
-    final Point mVisPoint; // used to retrieve global offset of focused view.
 
     boolean mTraversalScheduled;
     boolean mWillDrawSoon;
@@ -218,7 +217,6 @@
         mDirty = new Rect();
         mTempRect = new Rect();
         mVisRect = new Rect();
-        mVisPoint = new Point();
         mWinFrame = new Rect();
         mWindow = new W(this, context);
         mInputMethodCallback = new InputMethodCallback(this);
@@ -387,20 +385,25 @@
             if (mView == null) {
                 mView = view;
                 mWindowAttributes.copyFrom(attrs);
-                mCompatibilityInfo = mView.getContext().getResources().getCompatibilityInfo();
+
+                CompatibilityInfo compatibilityInfo =
+                        mView.getContext().getResources().getCompatibilityInfo();
+                mTranslator = compatibilityInfo.getTranslator(attrs);
                 boolean restore = false;
-                if (mCompatibilityInfo.mScalingRequired || !mCompatibilityInfo.mExpandable) {
+                if (attrs != null && mTranslator != null) {
                     restore = true;
-                    mWindowAttributes.backup();
+                    attrs.backup();
+                    mTranslator.translateWindowLayout(attrs);
                 }
-                if (!mCompatibilityInfo.mExpandable) {
-                    adjustWindowAttributesForCompatibleMode(mWindowAttributes);
-                }
+                if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
+
                 mSoftInputMode = attrs.softInputMode;
                 mWindowAttributesChanged = true;
                 mAttachInfo.mRootView = view;
-                mAttachInfo.mScalingRequired = mCompatibilityInfo.mScalingRequired;
-                mAttachInfo.mApplicationScale = mCompatibilityInfo.mApplicationScale;
+                mAttachInfo.mScalingRequired =
+                        mTranslator == null ? false : mTranslator.scalingRequired;
+                mAttachInfo.mApplicationScale =
+                        mTranslator == null ? 1.0f : mTranslator.applicationScale;
                 if (panelParentView != null) {
                     mAttachInfo.mPanelParentWindowToken
                             = panelParentView.getApplicationWindowToken();
@@ -421,15 +424,14 @@
                     mAttachInfo.mRootView = null;
                     unscheduleTraversals();
                     throw new RuntimeException("Adding window failed", e);
+                } finally {
+                    if (restore) {
+                        attrs.restore();
+                    }
                 }
 
-                if (restore) {
-                    mWindowAttributes.restore();
-                }
-
-                if (mCompatibilityInfo.mScalingRequired) {
-                    mAttachInfo.mContentInsets.scale(
-                            mCompatibilityInfo.mApplicationInvertedScale);
+                if (mTranslator != null) {
+                    mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
                 }
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
@@ -541,14 +543,14 @@
 
     public void invalidateChild(View child, Rect dirty) {
         checkThread();
-        if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
-        if (mCurScrollY != 0 || mCompatibilityInfo.mScalingRequired) {
+        if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+        if (mCurScrollY != 0 || mTranslator != null) {
             mTempRect.set(dirty);
             if (mCurScrollY != 0) {
                mTempRect.offset(0, -mCurScrollY);
             }
-            if (mCompatibilityInfo.mScalingRequired) {
-                mTempRect.scale(mCompatibilityInfo.mApplicationScale);
+            if (mTranslator != null) {
+                mTranslator.translateRectInAppWindowToScreen(mTempRect);
             }
             dirty = mTempRect;
         }
@@ -567,7 +569,7 @@
         return null;
     }
 
-     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
+    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
         if (child != mView) {
             throw new RuntimeException("child is not mine, honest!");
         }
@@ -628,14 +630,14 @@
         boolean viewVisibilityChanged = mViewVisibility != viewVisibility
                 || mNewSurfaceNeeded;
 
-        float appScale = mCompatibilityInfo.mApplicationScale;
+        float appScale = mAttachInfo.mApplicationScale;
 
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
             mWindowAttributesChanged = false;
             params = lp;
         }
-
+        Rect frame = mWinFrame;
         if (mFirst) {
             fullRedrawNeeded = true;
             mLayoutRequested = true;
@@ -660,11 +662,11 @@
             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
 
         } else {
-            desiredWindowWidth = mWinFrame.width();
-            desiredWindowHeight = mWinFrame.height();
+            desiredWindowWidth = frame.width();
+            desiredWindowHeight = frame.height();
             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
                 if (DEBUG_ORIENTATION) Log.v("ViewRoot",
-                        "View " + host + " resized to: " + mWinFrame);
+                        "View " + host + " resized to: " + frame);
                 fullRedrawNeeded = true;
                 mLayoutRequested = true;
                 windowResizesToFitContent = true;
@@ -810,7 +812,6 @@
                 }
             }
 
-            final Rect frame = mWinFrame;
             boolean initialized = false;
             boolean contentInsetsChanged = false;
             boolean visibleInsetsChanged;
@@ -883,7 +884,7 @@
             } catch (RemoteException e) {
             }
             if (DEBUG_ORIENTATION) Log.v(
-                    "ViewRoot", "Relayout returned: frame=" + mWinFrame + ", surface=" + mSurface);
+                    "ViewRoot", "Relayout returned: frame=" + frame + ", surface=" + mSurface);
 
             attachInfo.mWindowLeft = frame.left;
             attachInfo.mWindowTop = frame.top;
@@ -958,7 +959,6 @@
             if (Config.DEBUG && ViewDebug.profileLayout) {
                 startTime = SystemClock.elapsedRealtime();
             }
-
             host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
 
             if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -985,7 +985,10 @@
                         mTmpLocation[1] + host.mBottom - host.mTop);
 
                 host.gatherTransparentRegion(mTransparentRegion);
-                mTransparentRegion.scale(appScale);
+                if (mTranslator != null) {
+                    mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
+                }
+
                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                     mPreviousTransparentRegion.set(mTransparentRegion);
                     // reconfigure window manager
@@ -1016,15 +1019,17 @@
                     = givenContent.bottom = givenVisible.left = givenVisible.top
                     = givenVisible.right = givenVisible.bottom = 0;
             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
-            if (mCompatibilityInfo.mScalingRequired) {
-                insets.contentInsets.scale(appScale);
-                insets.visibleInsets.scale(appScale);
+            Rect contentInsets = insets.contentInsets;
+            Rect visibleInsets = insets.visibleInsets;
+            if (mTranslator != null) {
+                contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
+                visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
             }
             if (insetsPending || !mLastGivenInsets.equals(insets)) {
                 mLastGivenInsets.set(insets);
                 try {
                     sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
-                            insets.contentInsets, insets.visibleInsets);
+                            contentInsets, visibleInsets);
                 } catch (RemoteException e) {
                 }
             }
@@ -1167,8 +1172,8 @@
             mCurScrollY = yoff;
             fullRedrawNeeded = true;
         }
-        float appScale = mCompatibilityInfo.mApplicationScale;
-        boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
+        float appScale = mAttachInfo.mApplicationScale;
+        boolean scalingRequired = mAttachInfo.mScalingRequired;
 
         Rect dirty = mDirty;
         if (mUseGL) {
@@ -1187,8 +1192,8 @@
                     int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
                     try {
                         canvas.translate(0, -yoff);
-                        if (scalingRequired) {
-                            canvas.scale(appScale, appScale);
+                        if (mTranslator != null) {
+                            mTranslator.translateCanvas(canvas);
                         }
                         mView.draw(canvas);
                         if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -1239,7 +1244,6 @@
             int top = dirty.top;
             int right = dirty.right;
             int bottom = dirty.bottom;
-
             canvas = surface.lockCanvas(dirty);
 
             if (left != dirty.left || top != dirty.top || right != dirty.right ||
@@ -1295,8 +1299,8 @@
                 int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
                 try {
                     canvas.translate(0, -yoff);
-                    if (scalingRequired) {
-                        canvas.scale(appScale, appScale);
+                    if (mTranslator != null) {
+                        mTranslator.translateCanvas(canvas);
                     }
                     mView.draw(canvas);
                 } finally {
@@ -1599,10 +1603,9 @@
             } else {
                 didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
             }
-            if (event != null && mCompatibilityInfo.mScalingRequired) {
-                event.scale(mCompatibilityInfo.mApplicationInvertedScale);
+            if (event != null && mTranslator != null) {
+                mTranslator.translateEventInScreenToAppWindow(event);
             }
-
             try {
                 boolean handled;
                 if (mView != null && mAdded && event != null) {
@@ -1688,6 +1691,7 @@
         case RESIZED:
             Rect coveredInsets = ((Rect[])msg.obj)[0];
             Rect visibleInsets = ((Rect[])msg.obj)[1];
+
             if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
                     && mPendingContentInsets.equals(coveredInsets)
                     && mPendingVisibleInsets.equals(visibleInsets)) {
@@ -1722,7 +1726,7 @@
                         if (mGlWanted && !mUseGL) {
                             initializeGL();
                             if (mGlCanvas != null) {
-                                float appScale = mCompatibilityInfo.mApplicationScale;
+                                float appScale = mAttachInfo.mApplicationScale;
                                 mGlCanvas.setViewport(
                                         (int) (mWidth * appScale), (int) (mHeight * appScale));
                             }
@@ -2356,18 +2360,16 @@
 
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
+
+        float appScale = mAttachInfo.mApplicationScale;
         boolean restore = false;
-        float appScale = mCompatibilityInfo.mApplicationScale;
-        boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
-        if (params != null && !mCompatibilityInfo.mExpandable) {
+        if (params != null && mTranslator != null) {
             restore = true;
             params.backup();
-            adjustWindowAttributesForCompatibleMode(params);
+            mTranslator.translateWindowLayout(params);
         }
-        if (params != null && scalingRequired) {
-            if (!restore) params.backup();
-            restore = true;
-            params.scale(appScale);
+        if (params != null) {
+            if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
         }
         int relayoutResult = sWindowSession.relayout(
                 mWindow, params,
@@ -2378,44 +2380,16 @@
         if (restore) {
             params.restore();
         }
-        if (scalingRequired) {
-            float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
-            mPendingContentInsets.scale(invertedScale);
-            mPendingVisibleInsets.scale(invertedScale);
-            mWinFrame.scale(invertedScale);
+        
+        if (mTranslator != null) {
+            mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
+            mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
+            mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
         }
         return relayoutResult;
     }
 
     /**
-     * Adjust the window's layout parameter for compatibility mode. It replaces FILL_PARENT
-     * with the default window size, and centers if the window wanted to fill
-     * horizontally.
-     *
-     * @param attrs the window's layout params to adjust
-     */
-    private void adjustWindowAttributesForCompatibleMode(WindowManager.LayoutParams attrs) {
-        // fix app windows only
-        if (attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-            DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
-            // TODO: improve gravity logic
-            if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
-                attrs.width = metrics.widthPixels;
-                attrs.gravity |= Gravity.CENTER_HORIZONTAL;
-                mWindowAttributesChanged = attrs == mWindowAttributes;
-            }
-            if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
-                attrs.height = metrics.heightPixels;
-                attrs.gravity |= Gravity.TOP;
-                mWindowAttributesChanged = attrs == mWindowAttributes;
-            }
-            if (DEBUG_LAYOUT) {
-                Log.d(TAG, "Adjusted Attributes for compatibility : " + attrs);
-            }
-        }
-    }
-
-    /**
      * {@inheritDoc}
      */
     public void playSoundEffect(int effectId) {
@@ -2518,16 +2492,14 @@
                 + " visibleInsets=" + visibleInsets.toShortString()
                 + " reportDraw=" + reportDraw);
         Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
-        if (mCompatibilityInfo.mScalingRequired) {
-            float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
-            coveredInsets.scale(invertedScale);
-            visibleInsets.scale(invertedScale);
-            msg.arg1 = (int) (w * invertedScale);
-            msg.arg2 = (int) (h * invertedScale);
-        } else {
-            msg.arg1 = w;
-            msg.arg2 = h;
+        if (mTranslator != null) {
+            mTranslator.translateRectInScreenToAppWindow(coveredInsets);
+            mTranslator.translateRectInScreenToAppWindow(visibleInsets);
+            w *= mTranslator.applicationInvertedScale;
+            h *= mTranslator.applicationInvertedScale;
         }
+        msg.arg1 = w;
+        msg.arg2 = h;
         msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
         sendMessage(msg);
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e295d15..bdb86d7 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -483,6 +483,12 @@
          * {@hide} */
         public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
 
+        /** Window flag: special flag to let a window ignore the compatibility scaling.
+         * This is used by SurfaceView to create a window that does not scale the content.
+         *
+         * {@hide} */
+        public static final int FLAG_NO_COMPATIBILITY_SCALING = 0x00100000;
+
         /** Window flag: a special option intended for system dialogs.  When
          * this flag is set, the window will demand focus unconditionally when
          * it is created.
@@ -978,8 +984,9 @@
 
         /**
          * Scale the layout params' coordinates and size.
+         * @hide
          */
-        void scale(float scale) {
+        public void scale(float scale) {
             x *= scale;
             y *= scale;
             if (width > 0) {
@@ -997,14 +1004,13 @@
         void backup() {
             int[] backup = mCompatibilityParamsBackup;
             if (backup == null) {
-                // we backup 5 elements, x, y, width, height and gravity.
-                backup = mCompatibilityParamsBackup = new int[5];
+                // we backup 4 elements, x, y, width, height
+                backup = mCompatibilityParamsBackup = new int[4];
             }
             backup[0] = x;
             backup[1] = y;
             backup[2] = width;
             backup[3] = height;
-            backup[4] = gravity;
         }
 
         /**
@@ -1018,7 +1024,6 @@
                 y = backup[1];
                 width = backup[2];
                 height = backup[3];
-                gravity = backup[4];
             }
         }
 
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index dcba943..ec671d5 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -69,7 +69,24 @@
         }
         int value;
     }
-    
+
+    /**
+     * Enum for specifying the WebView's desired density.
+     * FAR makes 100% looking like in 240dpi
+     * MEDIUM makes 100% looking like in 160dpi
+     * CLOSE makes 100% looking like in 120dpi
+     * @hide Pending API council approval
+     */
+    public enum ZoomDensity {
+        FAR(150),      // 240dpi
+        MEDIUM(100),    // 160dpi
+        CLOSE(75);     // 120dpi
+        ZoomDensity(int size) {
+            value = size;
+        }
+        int value;
+    }
+
     /**
      * Default cache usage pattern  Use with {@link #setCacheMode}.
      */
@@ -105,6 +122,8 @@
         LOW
     }
 
+    // WebView associated with this WebSettings.
+    private WebView mWebView;
     // BrowserFrame used to access the native frame pointer.
     private BrowserFrame mBrowserFrame;
     // Flag to prevent multiple SYNC messages at one time.
@@ -145,6 +164,7 @@
     // Don't need to synchronize the get/set methods as they
     // are basic types, also none of these values are used in
     // native WebCore code.
+    private ZoomDensity     mDefaultZoom = ZoomDensity.MEDIUM;
     private RenderPriority  mRenderPriority = RenderPriority.NORMAL;
     private int             mOverrideCacheMode = LOAD_DEFAULT;
     private boolean         mSaveFormData = true;
@@ -237,9 +257,10 @@
      * Package constructor to prevent clients from creating a new settings
      * instance.
      */
-    WebSettings(Context context) {   
+    WebSettings(Context context, WebView webview) {
         mEventHandler = new EventHandler();
         mContext = context;
+        mWebView = webview;
         mDefaultTextEncoding = context.getString(com.android.internal.
                                                  R.string.default_text_encoding);
 
@@ -447,6 +468,31 @@
     }
 
     /**
+     * Set the default zoom density of the page. This should be called from UI
+     * thread.
+     * @param zoom A ZoomDensity value
+     * @see WebSettings.ZoomDensity
+     * @hide Pending API council approval
+     */
+    public void setDefaultZoom(ZoomDensity zoom) {
+        if (mDefaultZoom != zoom) {
+            mDefaultZoom = zoom;
+            mWebView.updateDefaultZoomDensity(zoom.value);
+        }
+    }
+
+    /**
+     * Get the default zoom density of the page. This should be called from UI
+     * thread.
+     * @return A ZoomDensity value
+     * @see WebSettings.ZoomDensity
+     * @hide Pending API council approval
+     */
+    public ZoomDensity getDefaultZoom() {
+        return mDefaultZoom;
+    }
+
+    /**
      * Enables using light touches to make a selection and activate mouseovers.
      */
     public void setLightTouchEnabled(boolean enabled) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1179c1c..429f0f9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -408,7 +408,7 @@
 
     // default scale. Depending on the display density.
     static int DEFAULT_SCALE_PERCENT;
-    private float DEFAULT_SCALE;
+    private float mDefaultScale;
 
     // set to true temporarily while the zoom control is being dragged
     private boolean mPreviewZoomOnly = false;
@@ -640,7 +640,7 @@
         mZoomFitPageButton.setOnClickListener(
             new View.OnClickListener() {
                 public void onClick(View v) {
-                    zoomWithPreview(DEFAULT_SCALE);
+                    zoomWithPreview(mDefaultScale);
                     updateZoomButtonsEnabled();
                 }
             });
@@ -663,7 +663,7 @@
             // or out.
             mZoomButtonsController.setZoomInEnabled(canZoomIn);
             mZoomButtonsController.setZoomOutEnabled(canZoomOut);
-            mZoomFitPageButton.setEnabled(mActualScale != DEFAULT_SCALE);
+            mZoomFitPageButton.setEnabled(mActualScale != mDefaultScale);
         }
         mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE:
                 View.GONE);
@@ -685,7 +685,7 @@
         mNavSlop = (int) (16 * density);
         // density adjusted scale factors
         DEFAULT_SCALE_PERCENT = (int) (100 * density);
-        DEFAULT_SCALE = density;
+        mDefaultScale = density;
         mActualScale = density;
         mInvActualScale = 1 / density;
         DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
@@ -694,6 +694,23 @@
         mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
     }
 
+    /* package */void updateDefaultZoomDensity(int zoomDensity) {
+        final float density = getContext().getResources().getDisplayMetrics().density
+                * 100 / zoomDensity;
+        if (Math.abs(density - mDefaultScale) > 0.01) {
+            float scaleFactor = density / mDefaultScale;
+            // adjust the limits
+            mNavSlop = (int) (16 * density);
+            DEFAULT_SCALE_PERCENT = (int) (100 * density);
+            DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
+            DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
+            mDefaultScale = density;
+            mMaxZoomScale *= scaleFactor;
+            mMinZoomScale *= scaleFactor;
+            setNewZoomScale(mActualScale * scaleFactor, false);
+        }
+    }
+
     /* package */ boolean onSavePassword(String schemePlusHost, String username,
             String password, final Message resumeMsg) {
        boolean rVal = false;
@@ -4172,8 +4189,8 @@
         float oldScale = mActualScale;
 
         // snap to DEFAULT_SCALE if it is close
-        if (scale > (DEFAULT_SCALE - 0.05) && scale < (DEFAULT_SCALE + 0.05)) {
-            scale = DEFAULT_SCALE;
+        if (scale > (mDefaultScale - 0.05) && scale < (mDefaultScale + 0.05)) {
+            scale = mDefaultScale;
         }
 
         setNewZoomScale(scale, false);
@@ -4554,9 +4571,11 @@
                     break;
                 }
                 case SWITCH_TO_LONGPRESS: {
-                    mTouchMode = TOUCH_DONE_MODE;
-                    performLongClick();
-                    updateTextEntry();
+                    if (!mPreventDrag) {
+                        mTouchMode = TOUCH_DONE_MODE;
+                        performLongClick();
+                        updateTextEntry();
+                    }
                     break;
                 }
                 case SWITCH_TO_ENTER:
@@ -4689,7 +4708,7 @@
                     int initialScale = msg.arg1;
                     int viewportWidth = msg.arg2;
                     // start a new page with DEFAULT_SCALE zoom scale.
-                    float scale = DEFAULT_SCALE;
+                    float scale = mDefaultScale;
                     if (mInitialScale > 0) {
                         scale = mInitialScale / 100.0f;
                     } else  {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index e2efb43..a5fa41e 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -139,7 +139,7 @@
         // ready.
         mEventHub = new EventHub();
         // Create a WebSettings object for maintaining all settings
-        mSettings = new WebSettings(mContext);
+        mSettings = new WebSettings(mContext, mWebView);
         // The WebIconDatabase needs to be initialized within the UI thread so
         // just request the instance here.
         WebIconDatabase.getInstance();
@@ -1560,6 +1560,20 @@
         // set the viewport settings from WebKit
         setViewportSettingsFromNative();
 
+        // adjust the default scale to match the density
+        if (WebView.DEFAULT_SCALE_PERCENT != 100) {
+            float adjust = (float) WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+            if (mViewportInitialScale > 0) {
+                mViewportInitialScale *= adjust;
+            }
+            if (mViewportMinimumScale > 0) {
+                mViewportMinimumScale *= adjust;
+            }
+            if (mViewportMaximumScale > 0) {
+                mViewportMaximumScale *= adjust;
+            }
+        }
+
         // infer the values if they are not defined.
         if (mViewportWidth == 0) {
             if (mViewportInitialScale == 0) {
@@ -1586,7 +1600,7 @@
                 mViewportMaximumScale = mViewportInitialScale;
             } else if (mViewportInitialScale == 0) {
                 mViewportInitialScale = mViewportMaximumScale;
-            }            
+            }
         }
         if (mViewportWidth < 0
                 && mViewportInitialScale == WebView.DEFAULT_SCALE_PERCENT) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 5dd3ec4..e84e5b0 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -80,6 +80,7 @@
  * @attr ref android.R.styleable#AutoCompleteTextView_dropDownSelector
  * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
  * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
+ * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
  */
 public class AutoCompleteTextView extends EditText implements Filter.FilterListener {
     static final boolean DEBUG = false;
@@ -101,6 +102,7 @@
     private int mDropDownAnchorId;
     private View mDropDownAnchorView;  // view is retrieved lazily from id once needed
     private int mDropDownWidth;
+    private int mDropDownHeight;
 
     private Drawable mDropDownListHighlight;
 
@@ -166,6 +168,8 @@
         // (for full screen width) or WRAP_CONTENT (to match the width of the anchored view).
         mDropDownWidth = a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownWidth,
                 ViewGroup.LayoutParams.WRAP_CONTENT);
+        mDropDownHeight = a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownHeight,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
 
         mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView,
                 R.layout.simple_dropdown_hint);
@@ -254,6 +258,34 @@
     public void setDropDownWidth(int width) {
         mDropDownWidth = width;
     }
+
+    /**
+     * <p>Returns the current height for the auto-complete drop down list. This can
+     * be a fixed height, or {@link ViewGroup.LayoutParams#FILL_PARENT} to fill
+     * the screen, or {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the height
+     * of the drop down's content.</p>
+     *
+     * @return the height for the drop down list
+     *
+     * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
+     */
+    public int getDropDownHeight() {
+        return mDropDownHeight;
+    }
+
+    /**
+     * <p>Sets the current height for the auto-complete drop down list. This can
+     * be a fixed height, or {@link ViewGroup.LayoutParams#FILL_PARENT} to fill
+     * the screen, or {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the height
+     * of the drop down's content.</p>
+     *
+     * @param height the height to use
+     *
+     * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
+     */
+    public void setDropDownHeight(int height) {
+        mDropDownHeight = height;
+    }
     
     /**
      * <p>Returns the id for the view that the auto-complete drop down list is anchored to.</p>
@@ -635,7 +667,7 @@
                     // event to prevent focus from moving.
                     clearListSelection();
                     mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
-                    mPopup.update();
+                    showDropDown();
                     return true;
                 } else {
                     // WARNING: Please read the comment where mListSelectionHidden
@@ -655,7 +687,7 @@
                     // by ensuring it has focus and getting its window out
                     // of touch mode.
                     mDropDownList.requestFocusFromTouch();
-                    mPopup.update();
+                    showDropDown();
 
                     switch (keyCode) {
                         // avoid passing the focus from the text view to the
@@ -1052,8 +1084,13 @@
      */
     public void showDropDown() {
         int height = buildDropDown();
+
+        int widthSpec = 0;
+        int heightSpec = 0;
+
+        boolean noInputMethod = mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+
         if (mPopup.isShowing()) {
-            int widthSpec;
             if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
                 // The call to PopupWindow's update method below can accept -1 for any
                 // value you do not want to update.
@@ -1063,20 +1100,51 @@
             } else {
                 widthSpec = mDropDownWidth;
             }
+
+            if (mDropDownHeight == ViewGroup.LayoutParams.FILL_PARENT) {
+                // The call to PopupWindow's update method below can accept -1 for any
+                // value you do not want to update.
+                heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.FILL_PARENT;
+                if (noInputMethod) {
+                    mPopup.setWindowLayoutMode(
+                            mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT ?
+                                    ViewGroup.LayoutParams.FILL_PARENT : 0, 0);
+                } else {
+                    mPopup.setWindowLayoutMode(
+                            mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT ?
+                                    ViewGroup.LayoutParams.FILL_PARENT : 0,
+                            ViewGroup.LayoutParams.FILL_PARENT);
+                }
+            } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+                heightSpec = height;
+            } else {
+                heightSpec = mDropDownHeight;
+            }
+
             mPopup.update(getDropDownAnchorView(), mDropDownHorizontalOffset,
-                    mDropDownVerticalOffset, widthSpec, height);
+                    mDropDownVerticalOffset, widthSpec, heightSpec);
         } else {
             if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
-                mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, 0);
+                widthSpec = ViewGroup.LayoutParams.FILL_PARENT;
             } else {
-                mPopup.setWindowLayoutMode(0, 0);
                 if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     mPopup.setWidth(getDropDownAnchorView().getWidth());
                 } else {
                     mPopup.setWidth(mDropDownWidth);
                 }
             }
-            mPopup.setHeight(height);
+
+            if (mDropDownHeight == ViewGroup.LayoutParams.FILL_PARENT) {
+                heightSpec = ViewGroup.LayoutParams.FILL_PARENT;
+            } else {
+                if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+                    mPopup.setHeight(height);
+                } else {
+                    mPopup.setHeight(mDropDownHeight);
+                }
+            }
+
+            mPopup.setWindowLayoutMode(widthSpec, heightSpec);
             mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
             
             // use outside touchable to dismiss drop down when touching outside of it, so
@@ -1134,7 +1202,11 @@
                         int position, long id) {
 
                     if (position != -1) {
-                        mDropDownList.mListSelectionHidden = false;
+                        DropDownListView dropDownList = mDropDownList;
+
+                        if (dropDownList != null) {
+                            dropDownList.mListSelectionHidden = false;
+                        }
                     }
                 }
 
@@ -1195,10 +1267,12 @@
         final int maxHeight = mPopup.getMaxAvailableHeight(
                 getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
 
-        final int measuredHeight = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
-                0, ListView.NO_POSITION, maxHeight - otherHeights, 2) + otherHeights;
+        if (mDropDownAlwaysVisible) {
+            return maxHeight;
+        }
 
-        return mDropDownAlwaysVisible ? maxHeight : measuredHeight;
+        return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
+                0, ListView.NO_POSITION, maxHeight - otherHeights, 2) + otherHeights;
     }
 
     private View getHintView(Context context) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 6532125d..f8a6f89 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3264,9 +3264,13 @@
         if (mChoiceMode == CHOICE_MODE_MULTIPLE) {
             mCheckStates.put(position, value);
         } else {
-            boolean oldValue = mCheckStates.get(position, false);
+            // Clear the old value: if something was selected and value == false
+            // then it is unselected
             mCheckStates.clear();
-            if (!oldValue) {
+            // If value == true, select the appropriate position
+            // this may end up selecting the value we just cleared but this way
+            // we don't have to first to a get(position)
+            if (value) {
                 mCheckStates.put(position, true);
             }
         }
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index b188c31..0c2cd55 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -49,7 +49,7 @@
  */
 public class PopupWindow {
     /**
-     * Mode for {@link #setInputMethodMode(int): the requirements for the
+     * Mode for {@link #setInputMethodMode(int)}: the requirements for the
      * input method should be based on the focusability of the popup.  That is
      * if it is focusable than it needs to work with the input method, else
      * it doesn't.
@@ -57,16 +57,15 @@
     public static final int INPUT_METHOD_FROM_FOCUSABLE = 0;
     
     /**
-     * Mode for {@link #setInputMethodMode(int): this popup always needs to
+     * Mode for {@link #setInputMethodMode(int)}: this popup always needs to
      * work with an input method, regardless of whether it is focusable.  This
      * means that it will always be displayed so that the user can also operate
      * the input method while it is shown.
      */
-    
     public static final int INPUT_METHOD_NEEDED = 1;
     
     /**
-     * Mode for {@link #setInputMethodMode(int): this popup never needs to
+     * Mode for {@link #setInputMethodMode(int)}: this popup never needs to
      * work with an input method, regardless of whether it is focusable.  This
      * means that it will always be displayed to use as much space on the
      * screen as needed, regardless of whether this covers the input method.
@@ -991,7 +990,7 @@
         
         int bottomEdge = displayFrame.bottom;
         if (ignoreBottomDecorations) {
-            bottomEdge = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight();
+            bottomEdge = anchor.getContext().getResources().getDisplayMetrics().heightPixels;
         }
         final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
         final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
@@ -1131,8 +1130,7 @@
             return;
         }
 
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                mPopupView.getLayoutParams();
+        WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
 
         boolean update = force;
 
@@ -1219,8 +1217,7 @@
             registerForScrollChanged(anchor, xoff, yoff);
         }
 
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                mPopupView.getLayoutParams();
+        WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
 
         if (updateDimension) {
             if (width == -1) {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 84cf2c8..e62dda5 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -20,8 +20,15 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.util.Poolable;
+import android.util.Pool;
+import android.util.Pools;
+import android.util.PoolableManager;
+import static android.util.Log.d;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewDebug;
@@ -32,6 +39,9 @@
 import java.util.Comparator;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.LinkedList;
+import java.util.HashSet;
+import java.util.ArrayList;
 
 /**
  * A Layout where the positions of the children can be described in relation to each other or to the
@@ -55,6 +65,10 @@
  */
 @RemoteView
 public class RelativeLayout extends ViewGroup {
+    private static final String LOG_TAG = "RelativeLayout";
+
+    private static final boolean DEBUG_GRAPH = false;
+
     public static final int TRUE = -1;
 
     /**
@@ -142,7 +156,12 @@
     private final Rect mSelfBounds = new Rect();
     private int mIgnoreGravity;
 
-    private static SortedSet<View> mTopToBottomLeftToRightSet = null;
+    private SortedSet<View> mTopToBottomLeftToRightSet = null;
+    
+    private boolean mDirtyHierarchy;
+    private View[] mSortedHorizontalChildren = new View[0];
+    private View[] mSortedVerticalChildren = new View[0];
+    private final DependencyGraph mGraph = new DependencyGraph();
 
     public RelativeLayout(Context context) {
         super(context);
@@ -232,7 +251,54 @@
     }
 
     @Override
+    public void requestLayout() {
+        super.requestLayout();
+        mDirtyHierarchy = true;
+    }
+
+    private void sortChildren() {
+        int count = getChildCount();
+        if (mSortedVerticalChildren.length != count) mSortedVerticalChildren = new View[count];
+        if (mSortedHorizontalChildren.length != count) mSortedHorizontalChildren = new View[count];
+
+        final DependencyGraph graph = mGraph;
+        graph.clear();
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            graph.add(child);
+        }
+
+        if (DEBUG_GRAPH) {
+            d(LOG_TAG, "=== Sorted vertical children");
+            graph.log(getResources(), ABOVE, BELOW, ALIGN_BASELINE, ALIGN_TOP, ALIGN_BOTTOM);
+            d(LOG_TAG, "=== Sorted horizontal children");
+            graph.log(getResources(), LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT);
+        }
+
+        graph.getSortedViews(mSortedVerticalChildren, ABOVE, BELOW, ALIGN_BASELINE,
+                ALIGN_TOP, ALIGN_BOTTOM);
+        graph.getSortedViews(mSortedHorizontalChildren, LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT);
+
+        if (DEBUG_GRAPH) {
+            d(LOG_TAG, "=== Ordered list of vertical children");
+            for (View view : mSortedVerticalChildren) {
+                DependencyGraph.printViewId(getResources(), view);
+            }
+            d(LOG_TAG, "=== Ordered list of horizontal children");
+            for (View view : mSortedHorizontalChildren) {
+                DependencyGraph.printViewId(getResources(), view);
+            }
+        }        
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mDirtyHierarchy) {
+            mDirtyHierarchy = false;
+            sortChildren();
+        }
+
         int myWidth = -1;
         int myHeight = -1;
 
@@ -261,7 +327,6 @@
             height = myHeight;
         }
 
-        int len = this.getChildCount();
         mHasBaselineAlignedChild = false;
 
         View ignore = null;
@@ -275,22 +340,50 @@
         int right = Integer.MIN_VALUE;
         int bottom = Integer.MIN_VALUE;
 
+        boolean offsetHorizontalAxis = false;
+        boolean offsetVerticalAxis = false;
+
         if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {
             ignore = findViewById(mIgnoreGravity);
         }
 
-        for (int i = 0; i < len; i++) {
-            View child = getChildAt(i);
+        final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY;
+        final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY;
+
+        View[] views = mSortedHorizontalChildren;
+        int count = views.length;
+        for (int i = 0; i < count; i++) {
+            View child = views[i];
             if (child.getVisibility() != GONE) {
                 LayoutParams params = (LayoutParams) child.getLayoutParams();
-                applySizeRules(params, myWidth, myHeight);
-                measureChild(child, params, myWidth, myHeight);
-                positionChild(child, params, myWidth, myHeight);
 
-                if (widthMode != MeasureSpec.EXACTLY) {
+                applyHorizontalSizeRules(params, myWidth);
+                measureChildHorizontal(child, params, myWidth, myHeight);
+                if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
+                    offsetHorizontalAxis = true;
+                }
+            }
+        }
+
+        views = mSortedVerticalChildren;
+        count = views.length;
+
+        for (int i = 0; i < count; i++) {
+            View child = views[i];
+            if (child.getVisibility() != GONE) {
+                LayoutParams params = (LayoutParams) child.getLayoutParams();
+                
+                applyVerticalSizeRules(params, myHeight);
+                measureChild(child, params, myWidth, myHeight);
+                if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {
+                    offsetVerticalAxis = true;
+                }
+
+                if (isWrapContentWidth) {
                     width = Math.max(width, params.mRight);
                 }
-                if (heightMode != MeasureSpec.EXACTLY) {
+
+                if (isWrapContentHeight) {
                     height = Math.max(height, params.mBottom);
                 }
 
@@ -307,15 +400,15 @@
         }
 
         if (mHasBaselineAlignedChild) {
-            for (int i = 0; i < len; i++) {
+            for (int i = 0; i < count; i++) {
                 View child = getChildAt(i);
                 if (child.getVisibility() != GONE) {
                     LayoutParams params = (LayoutParams) child.getLayoutParams();
                     alignBaseline(child, params);
 
                     if (child != ignore || verticalGravity) {
-                    left = Math.min(left, params.mLeft - params.leftMargin);
-                    top = Math.min(top, params.mTop - params.topMargin);
+                        left = Math.min(left, params.mLeft - params.leftMargin);
+                        top = Math.min(top, params.mTop - params.topMargin);
                     }
 
                     if (child != ignore || horizontalGravity) {
@@ -326,7 +419,7 @@
             }
         }
 
-        if (widthMode != MeasureSpec.EXACTLY) {
+        if (isWrapContentWidth) {
             // Width already has left padding in it since it was calculated by looking at
             // the right of each child view
             width += mPaddingRight;
@@ -337,8 +430,22 @@
 
             width = Math.max(width, getSuggestedMinimumWidth());
             width = resolveSize(width, widthMeasureSpec);
+
+            if (offsetHorizontalAxis) {
+                    for (int i = 0; i < count; i++) {
+                    View child = getChildAt(i);
+                    if (child.getVisibility() != GONE) {
+                        LayoutParams params = (LayoutParams) child.getLayoutParams();
+                        final int[] rules = params.getRules();
+                        if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
+                            centerHorizontal(child, params, width);
+                        }
+                    }
+                }
+            }
         }
-        if (heightMode != MeasureSpec.EXACTLY) {
+
+        if (isWrapContentHeight) {
             // Height already has top padding in it since it was calculated by looking at
             // the bottom of each child view
             height += mPaddingBottom;
@@ -349,6 +456,19 @@
 
             height = Math.max(height, getSuggestedMinimumHeight());
             height = resolveSize(height, heightMeasureSpec);
+
+            if (offsetVerticalAxis) {
+                for (int i = 0; i < count; i++) {
+                    View child = getChildAt(i);
+                    if (child.getVisibility() != GONE) {
+                        LayoutParams params = (LayoutParams) child.getLayoutParams();
+                        final int[] rules = params.getRules();
+                        if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
+                            centerVertical(child, params, height);
+                        }
+                    }
+                }
+            }
         }
 
         if (horizontalGravity || verticalGravity) {
@@ -362,7 +482,7 @@
             final int horizontalOffset = contentBounds.left - left;
             final int verticalOffset = contentBounds.top - top;
             if (horizontalOffset != 0 || verticalOffset != 0) {
-                for (int i = 0; i < len; i++) {
+                for (int i = 0; i < count; i++) {
                     View child = getChildAt(i);
                     if (child.getVisibility() != GONE && child != ignore) {
                         LayoutParams params = (LayoutParams) child.getLayoutParams();
@@ -416,9 +536,7 @@
      * @param myWidth Width of the the RelativeLayout
      * @param myHeight Height of the RelativeLayout
      */
-    private void measureChild(View child, LayoutParams params, int myWidth,
-            int myHeight) {
-
+    private void measureChild(View child, LayoutParams params, int myWidth, int myHeight) {
         int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
                 params.mRight, params.width,
                 params.leftMargin, params.rightMargin,
@@ -432,6 +550,21 @@
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
 
+    private void measureChildHorizontal(View child, LayoutParams params, int myWidth, int myHeight) {
+        int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
+                params.mRight, params.width,
+                params.leftMargin, params.rightMargin,
+                mPaddingLeft, mPaddingRight,
+                myWidth);
+        int childHeightMeasureSpec;
+        if (params.width == LayoutParams.FILL_PARENT) {
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.EXACTLY);
+        } else {
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.AT_MOST);
+        }
+        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+    }
+
     /**
      * Get a measure spec that accounts for all of the constraints on this view.
      * This includes size contstraints imposed by the RelativeLayout as well as
@@ -511,19 +644,9 @@
         return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
     }
 
-    /**
-     * After the child has been measured, assign it a position. Some views may
-     * already have final values for l,t,r,b. Others may have one or both edges
-     * unfixed (i.e. set to -1) in each dimension. These will get positioned
-     * based on which edge is fixed, the view's desired dimension, and whether
-     * or not it is centered.
-     *
-     * @param child Child to position
-     * @param params LayoutParams associated with child
-     * @param myWidth Width of the the RelativeLayout
-     * @param myHeight Height of the RelativeLayout
-     */
-    private void positionChild(View child, LayoutParams params, int myWidth, int myHeight) {
+    private boolean positionChildHorizontal(View child, LayoutParams params, int myWidth,
+            boolean wrapContent) {
+
         int[] rules = params.getRules();
 
         if (params.mLeft < 0 && params.mRight >= 0) {
@@ -534,13 +657,26 @@
             params.mRight = params.mLeft + child.getMeasuredWidth();
         } else if (params.mLeft < 0 && params.mRight < 0) {
             // Both left and right vary
-            if (0 != rules[CENTER_IN_PARENT] || 0 != rules[CENTER_HORIZONTAL]) {
-                centerHorizontal(child, params, myWidth);
+            if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
+                if (!wrapContent) {
+                    centerHorizontal(child, params, myWidth);
+                } else {
+                    params.mLeft = mPaddingLeft + params.leftMargin;
+                    params.mRight = params.mLeft + child.getMeasuredWidth();
+                }
+                return true;
             } else {
                 params.mLeft = mPaddingLeft + params.leftMargin;
                 params.mRight = params.mLeft + child.getMeasuredWidth();
             }
         }
+        return false;
+    }
+
+    private boolean positionChildVertical(View child, LayoutParams params, int myHeight,
+            boolean wrapContent) {
+
+        int[] rules = params.getRules();
 
         if (params.mTop < 0 && params.mBottom >= 0) {
             // Bottom is fixed, but top varies
@@ -550,26 +686,23 @@
             params.mBottom = params.mTop + child.getMeasuredHeight();
         } else if (params.mTop < 0 && params.mBottom < 0) {
             // Both top and bottom vary
-            if (0 != rules[CENTER_IN_PARENT] || 0 != rules[CENTER_VERTICAL]) {
-                centerVertical(child, params, myHeight);
+            if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
+                if (!wrapContent) {
+                    centerVertical(child, params, myHeight);
+                } else {
+                    params.mTop = mPaddingTop + params.topMargin;
+                    params.mBottom = params.mTop + child.getMeasuredHeight();
+                }
+                return true;
             } else {
                 params.mTop = mPaddingTop + params.topMargin;
                 params.mBottom = params.mTop + child.getMeasuredHeight();
             }
         }
+        return false;
     }
 
-    /**
-     * Set l,t,r,b values in the LayoutParams for one view based on its layout rules.
-     * Big assumption #1: All antecedents of this view have been sized & positioned
-     * Big assumption #2: The dimensions of the parent view (the RelativeLayout)
-     * are already known if they are needed.
-     *
-     * @param childParams LayoutParams for the view being positioned
-     * @param myWidth Width of the the RelativeLayout
-     * @param myHeight Height of the RelativeLayout
-     */
-    private void applySizeRules(LayoutParams childParams, int myWidth, int myHeight) {
+    private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth) {
         int[] rules = childParams.getRules();
         RelativeLayout.LayoutParams anchorParams;
 
@@ -629,6 +762,11 @@
                 // FIXME uh oh...
             }
         }
+    }
+
+    private void applyVerticalSizeRules(LayoutParams childParams, int myHeight) {
+        int[] rules = childParams.getRules();
+        RelativeLayout.LayoutParams anchorParams;
 
         childParams.mTop = -1;
         childParams.mBottom = -1;
@@ -691,18 +829,16 @@
     private View getRelatedView(int[] rules, int relation) {
         int id = rules[relation];
         if (id != 0) {
-            View v = findViewById(id);
-            if (v == null) {
-                return null;
-            }
+            DependencyGraph.Node node = mGraph.mKeyNodes.get(id);
+            if (node == null) return null;
+            View v = node.view;
 
             // Find the first non-GONE view up the chain
             while (v.getVisibility() == View.GONE) {
                 rules = ((LayoutParams) v.getLayoutParams()).getRules();
-                v = v.findViewById(rules[relation]);
-                if (v == null) {
-                    return null;
-                }
+                node = mGraph.mKeyNodes.get((rules[relation]));
+                if (node == null) return null;
+                v = node.view;
             }
 
             return v;
@@ -1033,4 +1169,284 @@
             return mRules;
         }
     }
+
+    private static class DependencyGraph {
+        /**
+         * List of all views in the graph.
+         */
+        private ArrayList<Node> mNodes = new ArrayList<Node>();
+
+        /**
+         * List of nodes in the graph. Each node is identified by its
+         * view id (see View#getId()).
+         */
+        private SparseArray<Node> mKeyNodes = new SparseArray<Node>();
+
+        /**
+         * Temporary data structure used to build the list of roots
+         * for this graph.
+         */
+        private LinkedList<Node> mRoots = new LinkedList<Node>();
+
+        /**
+         * Clears the graph.
+         */
+        void clear() {
+            final ArrayList<Node> nodes = mNodes;
+            final int count = nodes.size();
+
+            for (int i = 0; i < count; i++) {
+                nodes.get(i).release();
+            }
+            nodes.clear();
+
+            mKeyNodes.clear();
+            mRoots.clear();
+        }
+
+        /**
+         * Adds a view to the graph.
+         *
+         * @param view The view to be added as a node to the graph.
+         */
+        void add(View view) {
+            final int id = view.getId();
+            final Node node = Node.acquire(view);
+
+            if (id != View.NO_ID) {
+                mKeyNodes.put(id, node);
+            }
+
+            mNodes.add(node);
+        }
+
+        /**
+         * Builds a sorted list of views. The sorting order depends on the dependencies
+         * between the view. For instance, if view C needs view A to be processed first
+         * and view A needs view B to be processed first, the dependency graph
+         * is: B -> A -> C. The sorted array will contain views B, A and C in this order.
+         *
+         * @param sorted The sorted list of views. The length of this array must
+         *        be equal to getChildCount().
+         * @param rules The list of rules to take into account.
+         */
+        void getSortedViews(View[] sorted, int... rules) {
+            final LinkedList<Node> roots = findRoots(rules);
+            int index = 0;
+
+            while (roots.size() > 0) {
+                final Node node = roots.removeFirst();
+                final View view = node.view;
+                final int key = view.getId();
+
+                sorted[index++] = view;
+
+                final HashSet<Node> dependents = node.dependents;
+                for (Node dependent : dependents) {
+                    final SparseArray<Node> dependencies = dependent.dependencies;
+
+                    dependencies.remove(key);
+                    if (dependencies.size() == 0) {
+                        roots.add(dependent);
+                    }
+                }
+            }
+
+            if (index < sorted.length) {
+                throw new IllegalStateException("Circular dependencies cannot exist"
+                        + " in RelativeLayout");
+            }
+        }
+
+        /**
+         * Finds the roots of the graph. A root is a node with no dependency and
+         * with [0..n] dependents.
+         *
+         * @param rulesFilter The list of rules to consider when building the
+         *        dependencies
+         *
+         * @return A list of node, each being a root of the graph
+         */
+        private LinkedList<Node> findRoots(int[] rulesFilter) {
+            final SparseArray<Node> keyNodes = mKeyNodes;
+            final ArrayList<Node> nodes = mNodes;
+            final int count = nodes.size();
+
+            // Find roots can be invoked several times, so make sure to clear
+            // all dependents and dependencies before running the algorithm
+            for (int i = 0; i < count; i++) {
+                final Node node = nodes.get(i);
+                node.dependents.clear();
+                node.dependencies.clear();
+            }
+
+            // Builds up the dependents and dependencies for each node of the graph
+            for (int i = 0; i < count; i++) {
+                final Node node = nodes.get(i);
+
+                final LayoutParams layoutParams = (LayoutParams) node.view.getLayoutParams();
+                final int[] rules = layoutParams.mRules;
+                final int rulesCount = rulesFilter.length;
+
+                // Look only the the rules passed in parameter, this way we build only the
+                // dependencies for a specific set of rules
+                for (int j = 0; j < rulesCount; j++) {
+                    final int rule = rules[rulesFilter[j]];
+                    if (rule > 0) {
+                        // The node this node depends on
+                        final Node dependency = keyNodes.get(rule);
+                        if (dependency == node) {
+                            throw new IllegalStateException("A view cannot have a dependency" +
+                                    " on itself");
+                        }
+                        if (dependency == null) {
+                            continue;
+                        }
+                        // Add the current node as a dependent
+                        dependency.dependents.add(node);
+                        // Add a dependency to the current node
+                        node.dependencies.put(rule, dependency);
+                    }
+                }
+            }
+
+            final LinkedList<Node> roots = mRoots;
+            roots.clear();
+
+            // Finds all the roots in the graph: all nodes with no dependencies
+            for (int i = 0; i < count; i++) {
+                final Node node = nodes.get(i);
+                if (node.dependencies.size() == 0) roots.add(node);
+            }
+
+            return roots;
+        }
+
+        /**
+         * Prints the dependency graph for the specified rules.
+         *
+         * @param resources The context's resources to print the ids.
+         * @param rules The list of rules to take into account.
+         */
+        void log(Resources resources, int... rules) {
+            final LinkedList<Node> roots = findRoots(rules);
+            for (Node node : roots) {
+                printNode(resources, node);
+            }
+        }
+
+        static void printViewId(Resources resources, View view) {
+            if (view.getId() != View.NO_ID) {
+                d(LOG_TAG, resources.getResourceEntryName(view.getId()));
+            } else {
+                d(LOG_TAG, "NO_ID");
+            }
+        }
+
+        private static void appendViewId(Resources resources, Node node, StringBuilder buffer) {
+            if (node.view.getId() != View.NO_ID) {
+                buffer.append(resources.getResourceEntryName(node.view.getId()));
+            } else {
+                buffer.append("NO_ID");
+            }
+        }
+
+        private static void printNode(Resources resources, Node node) {
+            if (node.dependents.size() == 0) {
+                printViewId(resources, node.view);
+            } else {
+                for (Node dependent : node.dependents) {
+                    StringBuilder buffer = new StringBuilder();
+                    appendViewId(resources, node, buffer);
+                    printdependents(resources, dependent, buffer);
+                }
+            }
+        }
+
+        private static void printdependents(Resources resources, Node node, StringBuilder buffer) {
+            buffer.append(" -> ");
+            appendViewId(resources, node, buffer);
+
+            if (node.dependents.size() == 0) {
+                d(LOG_TAG, buffer.toString());
+            } else {
+                for (Node dependent : node.dependents) {
+                    StringBuilder subBuffer = new StringBuilder(buffer);
+                    printdependents(resources, dependent, subBuffer);
+                }
+            }
+        }
+
+        /**
+         * A node in the dependency graph. A node is a view, its list of dependencies
+         * and its list of dependents.
+         *
+         * A node with no dependent is considered a root of the graph.
+         */
+        static class Node implements Poolable<Node> {
+            /**
+             * The view representing this node in the layout.
+             */
+            View view;
+
+            /**
+             * The list of dependents for this node; a dependent is a node
+             * that needs this node to be processed first.
+             */
+            final HashSet<Node> dependents = new HashSet<Node>();
+
+            /**
+             * The list of dependencies for this node.
+             */
+            final SparseArray<Node> dependencies = new SparseArray<Node>();
+
+            /*
+             * START POOL IMPLEMENTATION
+             */
+            // The pool is static, so all nodes instances are shared across
+            // activities, that's why we give it a rather high limit
+            private static final int POOL_LIMIT = 100;
+            private static final Pool<Node> sPool = Pools.synchronizedPool(
+                    Pools.finitePool(new PoolableManager<Node>() {
+                        public Node newInstance() {
+                            return new Node();
+                        }
+
+                        public void onAcquired(Node element) {
+                        }
+
+                        public void onReleased(Node element) {
+                        }
+                    }, POOL_LIMIT)
+            );
+
+            private Node mNext;
+
+            public void setNextPoolable(Node element) {
+                mNext = element;
+            }
+
+            public Node getNextPoolable() {
+                return mNext;
+            }
+
+            static Node acquire(View view) {
+                final Node node = sPool.acquire();
+                node.view = view;
+
+                return node;
+            }
+
+            void release() {
+                view = null;
+                dependents.clear();
+                dependencies.clear();
+
+                sPool.release(this);
+            }
+            /*
+             * END POOL IMPLEMENTATION
+             */
+        }
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9479f9e..d8ed4f0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3681,12 +3681,13 @@
 
     @Override
     protected boolean isPaddingOffsetRequired() {
-        return mShadowRadius != 0;
+        return mShadowRadius != 0 || mDrawables != null;
     }
 
     @Override
     protected int getLeftPaddingOffset() {
-        return (int) Math.min(0, mShadowDx - mShadowRadius);
+        return getCompoundPaddingLeft() - mPaddingLeft +
+                (int) Math.min(0, mShadowDx - mShadowRadius);
     }
 
     @Override
@@ -3701,7 +3702,8 @@
 
     @Override
     protected int getRightPaddingOffset() {
-        return (int) Math.max(0, mShadowDx + mShadowRadius);
+        return -(getCompoundPaddingRight() - mPaddingRight) +
+                (int) Math.max(0, mShadowDx + mShadowRadius);
     }
 
     @Override
@@ -6665,9 +6667,10 @@
             } else if (getLineCount() == 1) {
                 switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                     case Gravity.LEFT:
-                        return (mLayout.getLineRight(0) - mScrollX - (mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight()) /
-                                getHorizontalFadingEdgeLength();
+                        final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() -
+                                getCompoundPaddingRight();
+                        final float lineWidth = mLayout.getLineWidth(0);
+                        return (lineWidth - textWidth) / getHorizontalFadingEdgeLength();
                     case Gravity.RIGHT:
                         return 0.0f;
                     case Gravity.CENTER_HORIZONTAL:
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index ce32754..4bac593 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -37,6 +37,7 @@
     void notePhoneOff();
     void notePhoneSignalStrength(in SignalStrength signalStrength);
     void notePhoneDataConnectionState(int dataType, boolean hasData);
+    void noteAirplaneMode(boolean isAirplaneMode);
     void noteWifiOn(int uid);
     void noteWifiOff(int uid);
     void noteWifiRunning();
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 84ed729..4bef265 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -41,6 +41,20 @@
         - adb: close the file
 */
     /**
+     * Ask the transport where, on local device storage, to keep backup state blobs.
+     * This is per-transport so that mock transports used for testing can coexist with
+     * "live" backup services without interfering with the live bookkeeping.  The
+     * returned string should be a name that is expected to be unambiguous among all
+     * available backup transports; the name of the class implementing the transport
+     * is a good choice.
+     *
+     * @return A unique name, suitable for use as a file or directory name, that the
+     *         Backup Manager could use to disambiguate state files associated with
+     *         different backup transports.
+     */
+    String transportDirName();
+
+    /**
      * Verify that this is a suitable time for a backup pass.  This should return zero
      * if a backup is reasonable right now, some positive value otherwise.  This method
      * will be called outside of the {@link #startSession}/{@link #endSession} pair.
@@ -54,63 +68,70 @@
     long requestBackupTime();
 
     /**
-     * Establish a connection to the back-end data repository, if necessary.  If the transport
-     * needs to initialize state that is not tied to individual applications' backup operations,
-     * this is where it should be done.
-     *
-     * @return Zero on success; a nonzero error code on failure.
-     */
-    int startSession();
-
-    /**
-     * Send one application's data to the backup destination.
+     * Send one application's data to the backup destination.  The transport may send
+     * the data immediately, or may buffer it.  After this is called, {@link #finishBackup}
+     * must be called to ensure the data is sent and recorded successfully.
      *
      * @param packageInfo The identity of the application whose data is being backed up.
      *   This specifically includes the signature list for the package.
      * @param data The data stream that resulted from invoking the application's
      *   BackupService.doBackup() method.  This may be a pipe rather than a file on
      *   persistent media, so it may not be seekable.
-     * @return Zero on success; a nonzero error code on failure.
+     * @return false if errors occurred (the backup should be aborted and rescheduled),
+     *   true if everything is OK so far (but {@link #finishBackup} must be called).
      */
-    int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor data);
+    boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
+
+    /**
+     * Finish sending application data to the backup destination.  This must be
+     * called after {@link #performBackup} to ensure that all data is sent.  Only
+     * when this method returns true can the backup be assumed to have succeeded.
+     *
+     * @return false if errors occurred (the backup should be aborted and rescheduled),
+     *   true if everything is OK so far (but {@link #finishBackup} must be called).
+     */
+    boolean finishBackup();
 
     /**
      * Get the set of backups currently available over this transport.
      *
-     * @return Descriptions of the set of restore images available for this device.
+     * @return Descriptions of the set of restore images available for this device,
+     *   or null if an error occurred (the attempt should be rescheduled).
      **/
     RestoreSet[] getAvailableRestoreSets();
 
     /**
-     * Get the set of applications from a given restore image.
+     * Start restoring application data from backup.  After calling this function,
+     * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData}
+     * to walk through the actual application data.
      *
      * @param token A backup token as returned by {@link #getAvailableRestoreSets}.
-     * @return An array of PackageInfo objects describing all of the applications
-     *   available for restore from this restore image.  This should include the list
-     *   of signatures for each package so that the Backup Manager can filter using that
-     *   information.
+     * @param packages List of applications to restore (if data is available).
+     *   Application data will be restored in the order given.
+     * @return false if errors occurred (the restore should be aborted and rescheduled),
+     *   true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
      */
-    PackageInfo[] getAppSet(int token);
+    boolean startRestore(long token, in PackageInfo[] packages);
 
     /**
-     * Retrieve one application's data from the backing store.
-     *
-     * @param token The backup record from which a restore is being requested.
-     * @param packageInfo The identity of the application whose data is being restored.
-     *   This must include the signature list for the package; it is up to the transport
-     *   to verify that the requested app's signatures match the saved backup record
-     *   because the transport cannot necessarily trust the client device.
-     * @param data An open, writable file into which the backup image should be stored.
-     * @return Zero on success; a nonzero error code on failure.
+     * Get the package name of the next application with data in the backup store.
+     * @return The name of one of the packages supplied to {@link #startRestore},
+     *   or "" (the empty string) if no more backup data is available,
+     *   or null if an error occurred (the restore should be aborted and rescheduled).
      */
-    int getRestoreData(int token, in PackageInfo packageInfo, in ParcelFileDescriptor data);
+    String nextRestorePackage();
 
     /**
-     * Terminate the backup session, closing files, freeing memory, and cleaning up whatever
-     * other state the transport required.
-     *
-     * @return Zero on success; a nonzero error code on failure.  Even on failure, the session
-     *         is torn down and must be restarted if another backup is attempted.
+     * Get the data for the application returned by {@link #nextRestorePackage}.
+     * @param data An open, writable file into which the backup data should be stored.
+     * @return false if errors occurred (the restore should be aborted and rescheduled),
+     *   true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
      */
-    int endSession();
+    boolean getRestoreData(in ParcelFileDescriptor outFd);
+
+    /**
+     * End a restore session (aborting any in-process data transfer as necessary),
+     * freeing any resources and connections used during the restore process.
+     */
+    void finishRestore();
 }
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 3dd71f3..c5d9d403 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -30,14 +30,14 @@
     private static final String TAG = "LocalTransport";
     private static final boolean DEBUG = true;
 
+    private static final String TRANSPORT_DIR_NAME
+            = "com.android.internal.backup.LocalTransport";
+
     private Context mContext;
     private PackageManager mPackageManager;
     private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
-    private FileFilter mDirFileFilter = new FileFilter() {
-        public boolean accept(File f) {
-            return f.isDirectory();
-        }
-    };
+    private PackageInfo[] mRestorePackages = null;
+    private int mRestorePackage = -1;  // Index into mRestorePackages
 
 
     public LocalTransport(Context context) {
@@ -46,26 +46,19 @@
         mPackageManager = context.getPackageManager();
     }
 
+
+    public String transportDirName() throws RemoteException {
+        return TRANSPORT_DIR_NAME;
+    }
+
     public long requestBackupTime() throws RemoteException {
         // any time is a good time for local backup
         return 0;
     }
 
-    public int startSession() throws RemoteException {
-        if (DEBUG) Log.v(TAG, "session started");
-        mDataDir.mkdirs();
-        return 0;
-    }
-
-    public int endSession() throws RemoteException {
-        if (DEBUG) Log.v(TAG, "session ended");
-        return 0;
-    }
-
-    public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
+    public boolean performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
             throws RemoteException {
         if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
-        int err = 0;
 
         File packageDir = new File(mDataDir, packageInfo.packageName);
         packageDir.mkdirs();
@@ -101,9 +94,8 @@
                     try {
                         entity.write(buf, 0, dataSize);
                     } catch (IOException e) {
-                        Log.e(TAG, "Unable to update key file "
-                                + entityFile.getAbsolutePath());
-                        err = -1;
+                        Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
+                        return false;
                     } finally {
                         entity.close();
                     }
@@ -111,14 +103,17 @@
                     entityFile.delete();
                 }
             }
+            return true;
         } catch (IOException e) {
             // oops, something went wrong.  abort the operation and return error.
-            Log.v(TAG, "Exception reading backup input:");
-            e.printStackTrace();
-            err = -1;
+            Log.v(TAG, "Exception reading backup input:", e);
+            return false;
         }
+    }
 
-        return err;
+    public boolean finishBackup() throws RemoteException {
+        if (DEBUG) Log.v(TAG, "finishBackup()");
+        return true;
     }
 
     // Restore handling
@@ -129,72 +124,66 @@
         return array;
     }
 
-    public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
-        if (DEBUG) Log.v(TAG, "getting app set " + token);
-        // the available packages are the extant subdirs of mDatadir
-        File[] packageDirs = mDataDir.listFiles(mDirFileFilter);
-        ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>();
-        for (File dir : packageDirs) {
-            try {
-                PackageInfo pkg = mPackageManager.getPackageInfo(dir.getName(),
-                        PackageManager.GET_SIGNATURES);
-                if (pkg != null) {
-                    packages.add(pkg);
-                }
-            } catch (NameNotFoundException e) {
-                // restore set contains data for a package not installed on the
-                // phone -- just ignore it.
-            }
-        }
-
-        if (DEBUG) {
-            Log.v(TAG, "Built app set of " + packages.size() + " entries:");
-            for (PackageInfo p : packages) {
-                Log.v(TAG, "    + " + p.packageName);
-            }
-        }
-
-        PackageInfo[] result = new PackageInfo[packages.size()];
-        return packages.toArray(result);
+    public boolean startRestore(long token, PackageInfo[] packages) {
+        if (DEBUG) Log.v(TAG, "start restore " + token);
+        mRestorePackages = packages;
+        mRestorePackage = -1;
+        return true;
     }
 
-    public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor outFd)
-            throws android.os.RemoteException {
-        if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName);
-        // we only support one hardcoded restore set
-        if (token != 0) return -1;
+    public String nextRestorePackage() {
+        if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+        while (++mRestorePackage < mRestorePackages.length) {
+            String name = mRestorePackages[mRestorePackage].packageName;
+            if (new File(mDataDir, name).isDirectory()) {
+                if (DEBUG) Log.v(TAG, "  nextRestorePackage() = " + name);
+                return name;
+            }
+        }
 
-        // the data for a given package is at a known location
-        File packageDir = new File(mDataDir, packageInfo.packageName);
+        if (DEBUG) Log.v(TAG, "  no more packages to restore");
+        return "";
+    }
+
+    public boolean getRestoreData(ParcelFileDescriptor outFd) {
+        if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+        if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
+        File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
 
         // The restore set is the concatenation of the individual record blobs,
         // each of which is a file in the package's directory
         File[] blobs = packageDir.listFiles();
-        if (DEBUG) Log.v(TAG, "   found " + blobs.length + " key files");
-        int err = 0;
-        if (blobs != null && blobs.length > 0) {
-            BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
-            try {
-                for (File f : blobs) {
-                    copyToRestoreData(f, out);
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Unable to read backup records");
-                err = -1;
-            }
+        if (blobs == null) {
+            Log.e(TAG, "Error listing directory: " + packageDir);
+            return false;  // nextRestorePackage() ensures the dir exists, so this is an error
         }
-        return err;
+
+        // We expect at least some data if the directory exists in the first place
+        if (DEBUG) Log.v(TAG, "  getRestoreData() found " + blobs.length + " key files");
+        BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
+        try {
+            for (File f : blobs) {
+                FileInputStream in = new FileInputStream(f);
+                try {
+                    int size = (int) f.length();
+                    byte[] buf = new byte[size];
+                    in.read(buf);
+                    String key = new String(Base64.decode(f.getName()));
+                    if (DEBUG) Log.v(TAG, "    ... key=" + key + " size=" + size);
+                    out.writeEntityHeader(key, size);
+                    out.writeEntityData(buf, size);
+                } finally {
+                    in.close();
+                }
+            }
+            return true;
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to read backup records", e);
+            return false;
+        }
     }
 
-    private void copyToRestoreData(File f, BackupDataOutput out) throws IOException {
-        FileInputStream in = new FileInputStream(f);
-        int size = (int) f.length();
-        byte[] buf = new byte[size];
-        in.read(buf);
-        String key = new String(Base64.decode(f.getName()));
-        if (DEBUG) Log.v(TAG, "   ... copy to stream: key=" + key
-                + " size=" + size);
-        out.writeEntityHeader(key, size);
-        out.writeEntityData(buf, size);
+    public void finishRestore() {
+        if (DEBUG) Log.v(TAG, "finishRestore()");
     }
 }
diff --git a/core/java/com/android/internal/backup/SystemBackupAgent.java b/core/java/com/android/internal/backup/SystemBackupAgent.java
new file mode 100644
index 0000000..6b396d7
--- /dev/null
+++ b/core/java/com/android/internal/backup/SystemBackupAgent.java
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.backup;
+
+import android.backup.AbsoluteFileBackupHelper;
+import android.backup.BackupHelperAgent;
+
+/**
+ * Backup agent for various system-managed data
+ */
+public class SystemBackupAgent extends BackupHelperAgent {
+    // the set of files that we back up whole, as absolute paths
+    String[] mFiles = {
+            /* WallpaperService.WALLPAPER_FILE */
+            "/data/data/com.android.settings/files/wallpaper",
+            };
+
+    public void onCreate() {
+        addHelper("system_files", new AbsoluteFileBackupHelper(this, mFiles));
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 16a3bad..a03802d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -191,6 +191,8 @@
     private final Map<String, KernelWakelockStats> mProcWakelockFileStats = 
             new HashMap<String, KernelWakelockStats>();
 
+    private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
+    
     // For debugging
     public BatteryStatsImpl() {
         mFile = mBackupFile = null;
@@ -714,6 +716,10 @@
             }
         }
 
+        boolean isRunningLocked() {
+            return mNesting > 0;
+        }
+
         void stopRunningLocked(BatteryStatsImpl stats) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
@@ -984,11 +990,11 @@
     }
 
     public void noteStartGps(int uid) {
-        mUidStats.get(uid).noteStartGps();
+        getUidStatsLocked(uid).noteStartGps();
     }
     
     public void noteStopGps(int uid) {
-        mUidStats.get(uid).noteStopGps();
+        getUidStatsLocked(uid).noteStopGps();
     }
 
     public void noteScreenOnLocked() {
@@ -1032,10 +1038,7 @@
     }
     
     public void noteUserActivityLocked(int uid, int event) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteUserActivityLocked(event);
-        }
+        getUidStatsLocked(uid).noteUserActivityLocked(event);
     }
     
     public void notePhoneOnLocked() {
@@ -1051,7 +1054,24 @@
             mPhoneOnTimer.stopRunningLocked(this);
         }
     }
-    
+
+    public void noteAirplaneModeLocked(boolean isAirplaneMode) {
+        final int bin = mPhoneSignalStrengthBin;
+        if (bin >= 0) {
+            if (!isAirplaneMode) {
+                if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
+                    mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
+                }
+            } else {
+                for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
+                    while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
+                        mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
+                    }
+                }
+            }
+        }
+    }
+
     public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
         // Bin the strength.
         int bin;
@@ -1115,16 +1135,10 @@
         }
         if (mWifiOnUid != uid) {
             if (mWifiOnUid >= 0) {
-                Uid u = mUidStats.get(mWifiOnUid);
-                if (u != null) {
-                    u.noteWifiTurnedOffLocked();
-                }
+                getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
             }
             mWifiOnUid = uid;
-            Uid u = mUidStats.get(uid);
-            if (u != null) {
-                u.noteWifiTurnedOnLocked();
-            }
+            getUidStatsLocked(uid).noteWifiTurnedOnLocked();
         }
     }
     
@@ -1134,10 +1148,7 @@
             mWifiOnTimer.stopRunningLocked(this);
         }
         if (mWifiOnUid >= 0) {
-            Uid u = mUidStats.get(mWifiOnUid);
-            if (u != null) {
-                u.noteWifiTurnedOffLocked();
-            }
+            getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
             mWifiOnUid = -1;
         }
     }
@@ -1147,10 +1158,7 @@
             mAudioOn = true;
             mAudioOnTimer.startRunningLocked(this);
         }
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteAudioTurnedOnLocked();
-        }
+        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
     }
     
     public void noteAudioOffLocked(int uid) {
@@ -1158,10 +1166,7 @@
             mAudioOn = false;
             mAudioOnTimer.stopRunningLocked(this);
         }
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteAudioTurnedOffLocked();
-        }
+        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
     }
 
     public void noteVideoOnLocked(int uid) {
@@ -1169,10 +1174,7 @@
             mVideoOn = true;
             mVideoOnTimer.startRunningLocked(this);
         }
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteVideoTurnedOnLocked();
-        }
+        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
     }
     
     public void noteVideoOffLocked(int uid) {
@@ -1180,10 +1182,7 @@
             mVideoOn = false;
             mVideoOnTimer.stopRunningLocked(this);
         }
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteVideoTurnedOffLocked();
-        }
+        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
     }
 
     public void noteWifiRunningLocked() {
@@ -1215,45 +1214,27 @@
     }
     
     public void noteFullWifiLockAcquiredLocked(int uid) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteFullWifiLockAcquiredLocked();
-        }
+        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
     }
 
     public void noteFullWifiLockReleasedLocked(int uid) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteFullWifiLockReleasedLocked();
-        }
+        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
     }
 
     public void noteScanWifiLockAcquiredLocked(int uid) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteScanWifiLockAcquiredLocked();
-        }
+        getUidStatsLocked(uid).noteScanWifiLockAcquiredLocked();
     }
 
     public void noteScanWifiLockReleasedLocked(int uid) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteScanWifiLockReleasedLocked();
-        }
+        getUidStatsLocked(uid).noteScanWifiLockReleasedLocked();
     }
 
     public void noteWifiMulticastEnabledLocked(int uid) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteWifiMulticastEnabledLocked();
-        }
+        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
     }
 
     public void noteWifiMulticastDisabledLocked(int uid) {
-        Uid u = mUidStats.get(uid);
-        if (u != null) {
-            u.noteWifiMulticastDisabledLocked();
-        }
+        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
     }
 
     @Override public long getScreenOnTime(long batteryRealtime, int which) {
@@ -2839,7 +2820,7 @@
     public void removeUidStatsLocked(int uid) {
         mUidStats.remove(uid);
     }
-    
+
     /**
      * Retrieve the statistics object for a particular process, creating
      * if needed.
@@ -2850,6 +2831,24 @@
     }
 
     /**
+     * Retrieve the statistics object for a particular process, given
+     * the name of the process.
+     * @param name process name
+     * @return the statistics object for the process
+     */
+    public Uid.Proc getProcessStatsLocked(String name, int pid) {
+        int uid;
+        if (mUidCache.containsKey(name)) {
+            uid = mUidCache.get(name);
+        } else {
+            uid = Process.getUidForPid(pid);
+            mUidCache.put(name, uid);
+        }
+        Uid u = getUidStatsLocked(uid);
+        return u.getProcessStatsLocked(name);
+    }
+
+    /**
      * Retrieve the statistics object for a particular process, creating
      * if needed.
      */
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index a37bf6e..4a8d8b1 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -219,12 +219,12 @@
     public double getAveragePower(String type, int level) {
         if (sPowerMap.containsKey(type)) {
             Object data = sPowerMap.get(type);
-            if (data instanceof double[]) {
-                final double[] values = (double[]) data;
-                if (values.length > level) {
+            if (data instanceof Double[]) {
+                final Double[] values = (Double[]) data;
+                if (values.length > level && level >= 0) {
                     return values[level];
-                } else if (values.length < 0) {
-                    return values[0];
+                } else if (level < 0) {
+                    return 0;
                 } else {
                     return values[values.length - 1];
                 }
diff --git a/core/java/com/android/internal/util/BitwiseInputStream.java b/core/java/com/android/internal/util/BitwiseInputStream.java
index 4757919..86f74f3 100644
--- a/core/java/com/android/internal/util/BitwiseInputStream.java
+++ b/core/java/com/android/internal/util/BitwiseInputStream.java
@@ -65,30 +65,31 @@
     /**
      * Read some data and increment the current position.
      *
-     * @param bits the amount of data to read (gte 0, lte 8)
+     * The 8-bit limit on access to bitwise streams is intentional to
+     * avoid endianness issues.
      *
+     * @param bits the amount of data to read (gte 0, lte 8)
      * @return byte of read data (possibly partially filled, from lsb)
      */
-    public byte read(int bits) throws AccessException {
+    public int read(int bits) throws AccessException {
         int index = mPos >>> 3;
         int offset = 16 - (mPos & 0x07) - bits;  // &7==%8
         if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) {
             throw new AccessException("illegal read " +
                 "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")");
         }
-        int data = (mBuf[index] & 0x00FF) << 8;
-        if (offset < 8) data |= (mBuf[index + 1] & 0xFF);
+        int data = (mBuf[index] & 0xFF) << 8;
+        if (offset < 8) data |= mBuf[index + 1] & 0xFF;
         data >>>= offset;
         data &= (-1 >>> (32 - bits));
         mPos += bits;
-        return (byte)data;
+        return data;
     }
 
     /**
      * Read data in bulk into a byte array and increment the current position.
      *
      * @param bits the amount of data to read
-     *
      * @return newly allocated byte array of read data
      */
     public byte[] readByteArray(int bits) throws AccessException {
diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java
index 1b974ce..70c0be8 100644
--- a/core/java/com/android/internal/util/BitwiseOutputStream.java
+++ b/core/java/com/android/internal/util/BitwiseOutputStream.java
@@ -82,6 +82,9 @@
     /**
      * Write some data and increment the current position.
      *
+     * The 8-bit limit on access to bitwise streams is intentional to
+     * avoid endianness issues.
+     *
      * @param bits the amount of data to write (gte 0, lte 8)
      * @param data to write, will be masked to expose only bits param from lsb
      */
@@ -95,8 +98,8 @@
         int offset = 16 - (mPos & 0x07) - bits;  // &7==%8
         data <<= offset;
         mPos += bits;
-        mBuf[index] |= (data >>> 8);
-        if (offset < 8) mBuf[index + 1] |= (data & 0x00FF);
+        mBuf[index] |= data >>> 8;
+        if (offset < 8) mBuf[index + 1] |= data & 0xFF;
     }
 
     /**
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 80c2489..888cb11 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -19,6 +19,7 @@
 	ActivityManager.cpp \
 	AndroidRuntime.cpp \
 	CursorWindow.cpp \
+	Time.cpp \
 	com_google_android_gles_jni_EGLImpl.cpp \
 	com_google_android_gles_jni_GLImpl.cpp.arm \
 	android_opengl_GLES10.cpp \
@@ -119,7 +120,8 @@
 	com_android_internal_graphics_NativeUtils.cpp \
 	android_backup_BackupDataInput.cpp \
 	android_backup_BackupDataOutput.cpp \
-	android_backup_FileBackupHelperBase.cpp
+	android_backup_FileBackupHelperBase.cpp \
+	android_backup_BackupHelperDispatcher.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7350348..c815301 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -158,6 +158,7 @@
 extern int register_android_backup_BackupDataInput(JNIEnv *env);
 extern int register_android_backup_BackupDataOutput(JNIEnv *env);
 extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
+extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -1131,6 +1132,7 @@
     REG_JNI(register_android_backup_BackupDataInput),
     REG_JNI(register_android_backup_BackupDataOutput),
     REG_JNI(register_android_backup_FileBackupHelperBase),
+    REG_JNI(register_android_backup_BackupHelperDispatcher),
 };
 
 /*
diff --git a/libs/ui/Time.cpp b/core/jni/Time.cpp
similarity index 98%
rename from libs/ui/Time.cpp
rename to core/jni/Time.cpp
index b5539135..f3037f3 100644
--- a/libs/ui/Time.cpp
+++ b/core/jni/Time.cpp
@@ -1,4 +1,4 @@
-#include <utils/TimeUtils.h>
+#include "TimeUtils.h"
 #include <stdio.h>
 #include <cutils/tztime.h>
 
diff --git a/include/utils/TimeUtils.h b/core/jni/TimeUtils.h
similarity index 100%
rename from include/utils/TimeUtils.h
rename to core/jni/TimeUtils.h
diff --git a/core/jni/android_backup_BackupHelperDispatcher.cpp b/core/jni/android_backup_BackupHelperDispatcher.cpp
new file mode 100644
index 0000000..2e3f0b9
--- /dev/null
+++ b/core/jni/android_backup_BackupHelperDispatcher.cpp
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BackupHelperDispatcher_native"
+#include <utils/Log.h>
+
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+
+#define VERSION_1_HEADER 0x01706c48  // 'Hlp'1 little endian
+
+namespace android
+{
+
+struct chunk_header_v1 {
+    int headerSize;
+    int version;
+    int dataSize; // corresponds to Header.chunkSize
+    int nameLength; // not including the NULL terminator, which is not written to the file
+};
+
+// java.io.FileDescriptor
+static jfieldID s_descriptorField = 0;
+static jfieldID s_chunkSizeField = 0;
+static jfieldID s_keyPrefixField = 0;
+
+static int
+readHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj)
+{
+    chunk_header_v1 flattenedHeader;
+    int fd;
+    ssize_t amt;
+    String8 keyPrefix;
+    char* buf;
+
+    fd = env->GetIntField(fdObj, s_descriptorField);
+
+    amt = read(fd, &flattenedHeader.headerSize, sizeof(flattenedHeader.headerSize));
+    if (amt != sizeof(flattenedHeader.headerSize)) {
+        return -1;
+    }
+
+    int remainingHeader = flattenedHeader.headerSize - sizeof(flattenedHeader.headerSize);
+
+    if (flattenedHeader.headerSize < (int)sizeof(chunk_header_v1)) {
+        LOGW("Skipping unknown header: %d bytes", flattenedHeader.headerSize);
+        if (remainingHeader > 0) {
+            lseek(fd, remainingHeader, SEEK_CUR);
+            // >0 means skip this chunk
+            return 1;
+        }
+    }
+
+    amt = read(fd, &flattenedHeader.version,
+            sizeof(chunk_header_v1)-sizeof(flattenedHeader.headerSize));
+    if (amt <= 0) {
+        LOGW("Failed reading chunk header");
+        return -1;
+    }
+    remainingHeader -= sizeof(chunk_header_v1)-sizeof(flattenedHeader.headerSize);
+
+    if (flattenedHeader.version != VERSION_1_HEADER) {
+        LOGW("Skipping unknown header version: 0x%08x, %d bytes", flattenedHeader.version,
+                flattenedHeader.headerSize);
+        if (remainingHeader > 0) {
+            lseek(fd, remainingHeader, SEEK_CUR);
+            // >0 means skip this chunk
+            return 1;
+        }
+    }
+
+#if 0
+    LOGD("chunk header:");
+    LOGD("  headerSize=%d", flattenedHeader.headerSize);
+    LOGD("  version=0x%08x", flattenedHeader.version);
+    LOGD("  dataSize=%d", flattenedHeader.dataSize);
+    LOGD("  nameLength=%d", flattenedHeader.nameLength);
+#endif
+
+    if (flattenedHeader.dataSize < 0 || flattenedHeader.nameLength < 0 ||
+            remainingHeader < flattenedHeader.nameLength) {
+        LOGW("Malformed V1 header remainingHeader=%d dataSize=%d nameLength=%d", remainingHeader,
+                flattenedHeader.dataSize, flattenedHeader.nameLength);
+        return -1;
+    }
+
+    buf = keyPrefix.lockBuffer(flattenedHeader.nameLength);
+    if (buf == NULL) {
+        LOGW("unable to allocate %d bytes", flattenedHeader.nameLength);
+        return -1;
+    }
+
+    amt = read(fd, buf, flattenedHeader.nameLength);
+    buf[flattenedHeader.nameLength] = 0;
+
+    keyPrefix.unlockBuffer(flattenedHeader.nameLength);
+
+    remainingHeader -= flattenedHeader.nameLength;
+
+    if (remainingHeader > 0) {
+        lseek(fd, remainingHeader, SEEK_CUR);
+    }
+
+    env->SetIntField(headerObj, s_chunkSizeField, flattenedHeader.dataSize);
+    env->SetObjectField(headerObj, s_keyPrefixField, env->NewStringUTF(keyPrefix.string()));
+
+    return 0;
+}
+
+static int
+skipChunk_native(JNIEnv* env, jobject clazz, jobject fdObj, jint bytesToSkip)
+{
+    int fd;
+
+    fd = env->GetIntField(fdObj, s_descriptorField);
+
+    lseek(fd, bytesToSkip, SEEK_CUR);
+
+    return 0;
+}
+
+static int
+padding_len(int len)
+{
+    len = len % 4;
+    return len == 0 ? len : 4 - len;
+}
+
+static int
+allocateHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj)
+{
+    int pos;
+    jstring nameObj;
+    int nameLength;
+    int namePadding;
+    int headerSize;
+    int fd;
+
+    fd = env->GetIntField(fdObj, s_descriptorField);
+
+    nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField);
+
+    nameLength = env->GetStringUTFLength(nameObj);
+    namePadding = padding_len(nameLength);
+
+    headerSize = sizeof(chunk_header_v1) + nameLength + namePadding;
+
+    pos = lseek(fd, 0, SEEK_CUR);
+
+    lseek(fd, headerSize, SEEK_CUR);
+    
+    return pos;
+}
+
+static int
+writeHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj, jint pos)
+{
+    int err;
+    chunk_header_v1 header;
+    int fd;
+    int namePadding;
+    int prevPos;
+    jstring nameObj;
+    const char* buf;
+
+    fd = env->GetIntField(fdObj, s_descriptorField);
+    prevPos = lseek(fd, 0, SEEK_CUR);
+
+    nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField);
+    header.nameLength = env->GetStringUTFLength(nameObj);
+    namePadding = padding_len(header.nameLength);
+
+    header.headerSize = sizeof(chunk_header_v1) + header.nameLength + namePadding;
+    header.version = VERSION_1_HEADER;
+    header.dataSize = prevPos - (pos + header.headerSize);
+
+    lseek(fd, pos, SEEK_SET);
+    err = write(fd, &header, sizeof(chunk_header_v1));
+    if (err != sizeof(chunk_header_v1)) {
+        return errno;
+    }
+
+    buf = env->GetStringUTFChars(nameObj, NULL);
+    err = write(fd, buf, header.nameLength);
+    env->ReleaseStringUTFChars(nameObj, buf);
+    if (err != header.nameLength) {
+        return errno;
+    }
+
+    if (namePadding != 0) {
+        int zero = 0;
+        err = write(fd, &zero, namePadding);
+        if (err != namePadding) {
+            return errno;
+        }
+    }
+
+    lseek(fd, prevPos, SEEK_SET);
+    return 0;
+}
+
+static const JNINativeMethod g_methods[] = {
+    { "readHeader_native",
+       "(Landroid/backup/BackupHelperDispatcher$Header;Ljava/io/FileDescriptor;)I",
+       (void*)readHeader_native },
+    { "skipChunk_native",
+        "(Ljava/io/FileDescriptor;I)I",
+        (void*)skipChunk_native },
+    { "allocateHeader_native",
+        "(Landroid/backup/BackupHelperDispatcher$Header;Ljava/io/FileDescriptor;)I",
+        (void*)allocateHeader_native },
+    { "writeHeader_native",
+       "(Landroid/backup/BackupHelperDispatcher$Header;Ljava/io/FileDescriptor;I)I",
+       (void*)writeHeader_native },
+};
+
+int register_android_backup_BackupHelperDispatcher(JNIEnv* env)
+{
+    jclass clazz;
+
+    clazz = env->FindClass("java/io/FileDescriptor");
+    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
+    s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
+    LOG_FATAL_IF(s_descriptorField == NULL,
+            "Unable to find descriptor field in java.io.FileDescriptor");
+    
+    clazz = env->FindClass("android/backup/BackupHelperDispatcher$Header");
+    LOG_FATAL_IF(clazz == NULL,
+            "Unable to find class android.backup.BackupHelperDispatcher.Header");
+    s_chunkSizeField = env->GetFieldID(clazz, "chunkSize", "I");
+    LOG_FATAL_IF(s_chunkSizeField == NULL,
+            "Unable to find chunkSize field in android.backup.BackupHelperDispatcher.Header");
+    s_keyPrefixField = env->GetFieldID(clazz, "keyPrefix", "Ljava/lang/String;");
+    LOG_FATAL_IF(s_keyPrefixField == NULL,
+            "Unable to find keyPrefix field in android.backup.BackupHelperDispatcher.Header");
+    
+    return AndroidRuntime::registerNativeMethods(env, "android/backup/BackupHelperDispatcher",
+            g_methods, NELEM(g_methods));
+}
+
+}
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9b92bc5..8e48b38 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -53,19 +53,33 @@
 static fields_t fields;
 static Mutex sLock;
 
-struct camera_context_t {
+// provides persistent context for calls from native code to Java
+class JNICameraContext: public CameraListener
+{
+public:
+    JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera);
+    ~JNICameraContext() { release(); }
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
+    virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
+    sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
+    void release();
+
+private:
+    void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);
+
     jobject     mCameraJObjectWeak;     // weak reference to java object
     jclass      mCameraJClass;          // strong reference to java class
     sp<Camera>  mCamera;                // strong reference to native object 
+    Mutex       mLock;
 };
 
-sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext)
+sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
 {
     sp<Camera> camera;
     Mutex::Autolock _l(sLock);
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
+    JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
     if (context != NULL) {
-        camera = context->mCamera;
+        camera = context->getCamera();
     }
     LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
     if (camera == 0) {
@@ -76,30 +90,104 @@
     return camera;
 }
 
-static void err_callback(status_t err, void *cookie)
+JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera)
 {
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-    if ((context == NULL) || (context->mCamera == 0)) return;
+    mCameraJObjectWeak = env->NewGlobalRef(weak_this);
+    mCameraJClass = (jclass)env->NewGlobalRef(clazz);
+    mCamera = camera;
+}
 
-    LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get());
-
-    int error;
-    switch (err) {
-    case DEAD_OBJECT:
-        error = kCameraErrorMediaServer;
-        break;
-    default:
-        error = kCameraErrorUnknown;
-        break;
-    }
-
+void JNICameraContext::release()
+{
+    LOGV("release");
+    Mutex::Autolock _l(mLock);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        LOGE("err_callback on dead VM");
+
+    if (mCameraJObjectWeak != NULL) {
+        env->DeleteGlobalRef(mCameraJObjectWeak);
+        mCameraJObjectWeak = NULL;
+    }
+    if (mCameraJClass != NULL) {
+        env->DeleteGlobalRef(mCameraJClass);
+        mCameraJClass = NULL;
+    }
+    mCamera.clear();
+}
+
+void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
+{
+    LOGV("notify");
+
+    // VM pointer will be NULL if object is released
+    Mutex::Autolock _l(mLock);
+    if (mCameraJObjectWeak == NULL) {
+        LOGW("callback on dead camera object");
         return;
     }
-    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-            context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+            mCameraJObjectWeak, msgType, ext1, ext2);
+}
+
+void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
+{
+    jbyteArray obj = NULL;
+
+    // allocate Java byte array and copy data
+    if (dataPtr != NULL) {
+        ssize_t offset;
+        size_t size;
+        sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
+        LOGV("postData: off=%d, size=%d", offset, size);
+        uint8_t *heapBase = (uint8_t*)heap->base();
+
+        if (heapBase != NULL) {
+            uint8_t *data = heapBase + offset;
+            obj = env->NewByteArray(size);
+            if (obj == NULL) {
+                LOGE("Couldn't allocate byte array for JPEG data");
+                env->ExceptionClear();
+            } else {
+                jbyte *bytes = env->GetByteArrayElements(obj, NULL);
+                memcpy(bytes, data, size);
+                env->ReleaseByteArrayElements(obj, bytes, 0);
+
+            }
+        } else {
+            LOGE("image heap is NULL");
+        }
+    }
+
+    // post image data to Java
+    env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+            mCameraJObjectWeak, msgType, 0, 0, obj);
+    if (obj) {
+        env->DeleteLocalRef(obj);
+    }
+}
+
+void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
+{
+    // VM pointer will be NULL if object is released
+    Mutex::Autolock _l(mLock);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    // return data based on callback type
+    switch(msgType) {
+    case CAMERA_MSG_VIDEO_FRAME:
+        // should never happen
+        break;
+    // don't return raw data to Java
+    case CAMERA_MSG_RAW_IMAGE:
+        LOGV("rawCallback");
+        env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+                mCameraJObjectWeak, msgType, 0, 0, NULL);
+        break;
+    default:
+        LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
+        copyAndPost(env, dataPtr, msgType);
+        break;
+    }
 }
 
 // connect to camera service
@@ -127,19 +215,12 @@
 
     // We use a weak reference so the Camera object can be garbage collected.
     // The reference is only used as a proxy for callbacks.
-    camera_context_t* context = new camera_context_t;
-    context->mCameraJObjectWeak = env->NewGlobalRef(weak_this);
-    context->mCameraJClass = (jclass)env->NewGlobalRef(clazz);
-    context->mCamera = camera;
+    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
+    context->incStrong(thiz);
+    camera->setListener(context);
 
     // save context in opaque field
-    env->SetIntField(thiz, fields.context, (int)context);
-
-    LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p",
-            (int)context->mCameraJObjectWeak, (int)thiz, context);
-
-    // set error callback
-    camera->setErrorCallback(err_callback, context);
+    env->SetIntField(thiz, fields.context, (int)context.get());
 }
 
 // disconnect from camera service
@@ -148,11 +229,11 @@
 // finalizer is invoked later.
 static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
 {
-    camera_context_t* context = NULL;
+    JNICameraContext* context = NULL;
     sp<Camera> camera;
     {
         Mutex::Autolock _l(sLock);
-        context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
+        context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
 
         // Make sure we do not attempt to callback on a deleted Java object.
         env->SetIntField(thiz, fields.context, 0);
@@ -160,21 +241,18 @@
 
     // clean up if release has not been called before
     if (context != NULL) {
-        camera = context->mCamera;
-        context->mCamera.clear();
+        camera = context->getCamera();
+        context->release();
         LOGV("native_release: context=%p camera=%p", context, camera.get());
 
         // clear callbacks
         if (camera != NULL) {
-            camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP);
-            camera->setErrorCallback(NULL, NULL);
+            camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
             camera->disconnect();
-            env->DeleteGlobalRef(context->mCameraJObjectWeak);
-            env->DeleteGlobalRef(context->mCameraJClass);
         }
 
         // remove context to prevent further Java access
-        delete context;
+        context->decStrong(thiz);
     }
 }
 
@@ -190,48 +268,6 @@
     }
 }
 
-static void preview_callback(const sp<IMemory>& mem, void *cookie)
-{
-    LOGV("preview_callback");
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        LOGE("preview_callback on dead VM");
-        return;
-    }
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-    if ((context == NULL) || (context->mCamera == 0)) {
-        LOGW("context or camera is NULL in preview_callback");
-        return;
-    }
-    LOGV("native_release: context=%p camera=%p", context, context->mCamera.get());
-
-    int arg1 = 0, arg2 = 0;
-    jobject obj = NULL;
-
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
-    uint8_t *data = ((uint8_t *)heap->base()) + offset;
-
-    jbyteArray array = env->NewByteArray(size);
-    if (array == NULL) {
-        LOGE("Couldn't allocate byte array for YUV data");
-        env->ExceptionClear();
-        return;
-    }
-
-    jbyte *bytes = env->GetByteArrayElements(array, NULL);
-    memcpy(bytes, data, size);
-    env->ReleaseByteArrayElements(array, bytes, 0);
-
-    obj = array;
-
-    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-            context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj);
-    env->DeleteLocalRef(array);
-}
-
 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
 {
     LOGV("startPreview");
@@ -267,7 +303,7 @@
     // Important: Only install preview_callback if the Java code has called
     // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
     // each preview frame for nothing.
-    camera_context_t* context;
+    JNICameraContext* context;
     sp<Camera> camera = get_native_camera(env, thiz, &context);
     if (camera == 0) return;
 
@@ -277,130 +313,32 @@
     } else {
         callback_flag = FRAME_CALLBACK_FLAG_NOOP;
     }
-    camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag);
-}
-
-static void autofocus_callback_impl(bool success, void *cookie)
-{
-    LOGV("autoFocusCallback");
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        LOGE("autofocus_callback on dead VM");
-        return;
-    }
-    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-            context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL);
+    camera->setPreviewCallbackFlags(callback_flag);
 }
 
 static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
 {
     LOGV("autoFocus");
-    camera_context_t* context;
+    JNICameraContext* context;
     sp<Camera> c = get_native_camera(env, thiz, &context);
     if (c == 0) return;
 
-    c->setAutoFocusCallback(autofocus_callback_impl, context);
     if (c->autoFocus() != NO_ERROR) {
         jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed");
     }
 }
 
-static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
-{
-    LOGV("jpegCallback");
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        LOGE("jpeg`_callback on dead VM");
-        return;
-    }
-    int arg1 = 0, arg2 = 0;
-    jobject obj = NULL;
-
-    if (mem == NULL) {
-        env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-                                  context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL);
-        return;
-    }
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-    LOGV("jpeg_callback: mem off=%d, size=%d", offset, size);
-
-    uint8_t *heap_base = (uint8_t *)heap->base();
-    if (heap_base == NULL) {
-        LOGE("YUV heap is NULL");
-        return;
-    }
-
-    uint8_t *data = heap_base + offset;
-
-    jbyteArray array = env->NewByteArray(size);
-    if (array == NULL) {
-        LOGE("Couldn't allocate byte array for JPEG data");
-        env->ExceptionClear();
-        return;
-    }
-
-    jbyte *bytes = env->GetByteArrayElements(array, NULL);
-    memcpy(bytes, data, size);
-    env->ReleaseByteArrayElements(array, bytes, 0);
-
-    obj = array;
-
-    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-                              context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj);
-    env->DeleteLocalRef(array);
-}
-
-static void shutter_callback_impl(void *cookie)
-{
-    LOGV("shutterCallback");
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        LOGE("shutter_callback on dead VM");
-        return;
-    }
-    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-                              context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL);
-}
-
-static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
-                         void *cookie)
-{
-    LOGV("rawCallback");
-    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        LOGE("raw_callback on dead VM");
-        return;
-    }
-    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
-                              context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL);
-}
-
 static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
 {
     LOGV("takePicture");
-    camera_context_t* context;
+    JNICameraContext* context;
     sp<Camera> camera = get_native_camera(env, thiz, &context);
     if (camera == 0) return;
 
-    camera->setShutterCallback(shutter_callback_impl, context);
-    camera->setRawCallback(raw_callback, context);
-    camera->setJpegCallback(jpeg_callback, context);
     if (camera->takePicture() != NO_ERROR) {
         jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
         return;
     }
-
-    return;
 }
 
 static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index 7c208e9..98f4e03 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -23,7 +23,7 @@
 #include "jni.h"
 #include "utils/misc.h"
 #include "android_runtime/AndroidRuntime.h"
-#include <utils/TimeUtils.h>
+#include "TimeUtils.h"
 #include <nativehelper/JNIHelp.h>
 #include <cutils/tztime.h>
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d147bcc..2d90ba4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -535,7 +535,7 @@
                                                           jint keyboard, jint keyboardHidden,
                                                           jint navigation,
                                                           jint screenWidth, jint screenHeight,
-                                                          jint sdkVersion)
+                                                          jint screenLayout, jint sdkVersion)
 {
     AssetManager* am = assetManagerForJavaObject(env, clazz);
     if (am == NULL) {
@@ -557,6 +557,7 @@
     config.navigation = (uint8_t)navigation;
     config.screenWidth = (uint16_t)screenWidth;
     config.screenHeight = (uint16_t)screenHeight;
+    config.screenLayout = (uint8_t)screenLayout;
     config.sdkVersion = (uint16_t)sdkVersion;
     config.minorVersion = 0;
     am->setConfiguration(config, locale8);
@@ -1567,7 +1568,7 @@
         (void*) android_content_AssetManager_setLocale },
     { "getLocales",      "()[Ljava/lang/String;",
         (void*) android_content_AssetManager_getLocales },
-    { "setConfiguration", "(IILjava/lang/String;IIIIIIIII)V",
+    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIII)V",
         (void*) android_content_AssetManager_setConfiguration },
     { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
         (void*) android_content_AssetManager_getResourceIdentifier },
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 945a325..aee0ed7 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -269,9 +269,9 @@
 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
                                               jint pid, jint pri)
 {
-    if (pri == ANDROID_PRIORITY_BACKGROUND) {
+    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
         add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT);
-    } else if (getpriority(PRIO_PROCESS, pid) == ANDROID_PRIORITY_BACKGROUND) {
+    } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
         add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT);
     }
 
@@ -496,7 +496,7 @@
                 const String8& field = fields[i];
                 if (strncmp(p, field.string(), field.length()) == 0) {
                     p += field.length();
-                    while (*p == ' ') p++;
+                    while (*p == ' ' || *p == '\t') p++;
                     char* num = p;
                     while (*p >= '0' && *p <= '9') p++;
                     skipToEol = *p != '\n';
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index df6151d..599360f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -973,7 +973,7 @@
     <permission android:name="android.permission.BACKUP"
         android:label="@string/permlab_backup"
         android:description="@string/permdesc_backup"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Allows an application to tell the AppWidget service which application
          can access AppWidget's data.  The normal user flow is that a user
@@ -1000,6 +1000,7 @@
                  android:hasCode="false"
                  android:label="@string/android_system_label"
                  android:allowClearUserData="false"
+                 android:backupAgent="com.android.internal.backup.SystemBackupAgent"
                  android:icon="@drawable/ic_launcher_android">
         <activity android:name="com.android.internal.app.ChooserActivity"
                 android:theme="@style/Theme.Dialog.Alert"
diff --git a/core/res/res/drawable/progress.xml b/core/res/res/drawable/progress.xml
deleted file mode 100644
index d270520..0000000
--- a/core/res/res/drawable/progress.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/progress.xml
-**
-** Copyright 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.
-*/
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@android:drawable/progress_circular_background" />
-    <item>
-        <shape android:shape="ring"
-               android:innerRadiusRatio="3.4"
-               android:thicknessRatio="6.0">
-            <gradient
-                   android:useLevel="true"
-                   android:type="sweep"
-                   android:startColor="#ff000000"
-                   android:endColor="#ffffffff" />
-        </shape>
-    </item>
-    <item>
-        <rotate
-            android:pivotX="50%" android:pivotY="50%"
-            android:fromDegrees="0" android:toDegrees="360"
-            android:drawable="@android:drawable/progress_particle" />
-    </item>
-</layer-list>
diff --git a/core/res/res/drawable/progress_circular_background.png b/core/res/res/drawable/progress_circular_background.png
deleted file mode 100644
index 7c637fd..0000000
--- a/core/res/res/drawable/progress_circular_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/progress_circular_background_small.png b/core/res/res/drawable/progress_circular_background_small.png
deleted file mode 100644
index 6b8ba9b..0000000
--- a/core/res/res/drawable/progress_circular_background_small.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/progress_circular_indeterminate.png b/core/res/res/drawable/progress_circular_indeterminate.png
deleted file mode 100644
index 125a264..0000000
--- a/core/res/res/drawable/progress_circular_indeterminate.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/progress_indeterminate.xml b/core/res/res/drawable/progress_indeterminate.xml
deleted file mode 100644
index 1bf715e5..0000000
--- a/core/res/res/drawable/progress_indeterminate.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/progress.xml
-**
-** Copyright 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.
-*/
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:drawable="@android:drawable/progress_circular_background" />
-
-    <item><rotate
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fromDegrees="0"
-        android:toDegrees="360"
-        android:drawable="@android:drawable/progress_circular_indeterminate" />
-    </item>
-</layer-list>
diff --git a/core/res/res/drawable/progress_particle.png b/core/res/res/drawable/progress_particle.png
deleted file mode 100644
index 9160108..0000000
--- a/core/res/res/drawable/progress_particle.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background.9.png b/core/res/res/drawable/search_dropdown_background.9.png
old mode 100755
new mode 100644
index a6923b7c..804260a
--- a/core/res/res/drawable/search_dropdown_background.9.png
+++ b/core/res/res/drawable/search_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background_apps.9.png b/core/res/res/drawable/search_dropdown_background_apps.9.png
deleted file mode 100644
index 804260a..0000000
--- a/core/res/res/drawable/search_dropdown_background_apps.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner.xml b/core/res/res/drawable/search_spinner.xml
index 34c163d..31a77c3 100644
--- a/core/res/res/drawable/search_spinner.xml
+++ b/core/res/res/drawable/search_spinner.xml
@@ -2,7 +2,7 @@
 <!--
 /*
 **
-** Copyright 2008, 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. 
@@ -17,20 +17,9 @@
 ** limitations under the License.
 */
 -->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="false">
-    <item android:drawable="@drawable/search_spinner_anim1" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim2" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim3" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim4" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim5" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim6" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim7" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim8" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim9" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim10" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim11" android:duration="150" />
-    <item android:drawable="@drawable/search_spinner_anim12" android:duration="150" />
-</animation-list>
-
+<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/spinner_black_20"
+    android:pivotX="50%"
+    android:pivotY="50%"
+    android:framesCount="12"
+    android:frameDuration="100" />
diff --git a/core/res/res/drawable/search_spinner_anim10.png b/core/res/res/drawable/search_spinner_anim10.png
deleted file mode 100755
index 9611d97..0000000
--- a/core/res/res/drawable/search_spinner_anim10.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim11.png b/core/res/res/drawable/search_spinner_anim11.png
deleted file mode 100755
index 4261704..0000000
--- a/core/res/res/drawable/search_spinner_anim11.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim12.png b/core/res/res/drawable/search_spinner_anim12.png
deleted file mode 100755
index 0602314..0000000
--- a/core/res/res/drawable/search_spinner_anim12.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim2.png b/core/res/res/drawable/search_spinner_anim2.png
deleted file mode 100755
index 05d58e0..0000000
--- a/core/res/res/drawable/search_spinner_anim2.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim3.png b/core/res/res/drawable/search_spinner_anim3.png
deleted file mode 100755
index 69fa9c1..0000000
--- a/core/res/res/drawable/search_spinner_anim3.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim4.png b/core/res/res/drawable/search_spinner_anim4.png
deleted file mode 100755
index 9201bac..0000000
--- a/core/res/res/drawable/search_spinner_anim4.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim5.png b/core/res/res/drawable/search_spinner_anim5.png
deleted file mode 100755
index f0c7101..0000000
--- a/core/res/res/drawable/search_spinner_anim5.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim6.png b/core/res/res/drawable/search_spinner_anim6.png
deleted file mode 100755
index 99d1d4e..0000000
--- a/core/res/res/drawable/search_spinner_anim6.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim7.png b/core/res/res/drawable/search_spinner_anim7.png
deleted file mode 100755
index 8ca3358..0000000
--- a/core/res/res/drawable/search_spinner_anim7.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim8.png b/core/res/res/drawable/search_spinner_anim8.png
deleted file mode 100755
index 408d723..0000000
--- a/core/res/res/drawable/search_spinner_anim8.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim9.png b/core/res/res/drawable/search_spinner_anim9.png
deleted file mode 100755
index 42a2c65..0000000
--- a/core/res/res/drawable/search_spinner_anim9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/search_spinner_anim1.png b/core/res/res/drawable/spinner_black_20.png
similarity index 100%
rename from core/res/res/drawable/search_spinner_anim1.png
rename to core/res/res/drawable/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/layout/character_picker.xml b/core/res/res/layout/character_picker.xml
index bb4955a..0344849 100644
--- a/core/res/res/layout/character_picker.xml
+++ b/core/res/res/layout/character_picker.xml
@@ -23,8 +23,8 @@
         android:id="@+id/characterPicker"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="12dp"
-        android:verticalSpacing="8dp"
+        android:padding="4dp"
+        android:verticalSpacing="4dp"
         android:horizontalSpacing="8dp"
         android:stretchMode="spacingWidth"
         android:gravity="left"
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index 54ab6de..13e66aa 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -76,6 +76,7 @@
                 android:ellipsize="end"
                 android:inputType="text|textAutoComplete"
                 android:dropDownWidth="fill_parent"
+                android:dropDownHeight="fill_parent"
                 android:dropDownAnchor="@id/search_plate"
                 android:dropDownVerticalOffset="-9dip"
                 android:popupBackground="@android:drawable/search_dropdown_background"
diff --git a/core/res/res/values-de-rAT/donottranslate-cldr.xml b/core/res/res/values-de-rAT/donottranslate-cldr.xml
index cd7cba8..27624a3 100644
--- a/core/res/res/values-de-rAT/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rAT/donottranslate-cldr.xml
@@ -2,10 +2,43 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="month_long_standalone_january">Jänner</string>
+    <string name="month_long_standalone_february">Februar</string>
+    <string name="month_long_standalone_march">März</string>
+    <string name="month_long_standalone_april">April</string>
+    <string name="month_long_standalone_may">Mai</string>
+    <string name="month_long_standalone_june">Juni</string>
+    <string name="month_long_standalone_july">Juli</string>
+    <string name="month_long_standalone_august">August</string>
+    <string name="month_long_standalone_september">September</string>
+    <string name="month_long_standalone_october">Oktober</string>
+    <string name="month_long_standalone_november">November</string>
+    <string name="month_long_standalone_december">Dezember</string>
 
     <string name="month_long_january">Jänner</string>
+    <string name="month_long_february">Februar</string>
+    <string name="month_long_march">März</string>
+    <string name="month_long_april">April</string>
+    <string name="month_long_may">Mai</string>
+    <string name="month_long_june">Juni</string>
+    <string name="month_long_july">Juli</string>
+    <string name="month_long_august">August</string>
+    <string name="month_long_september">September</string>
+    <string name="month_long_october">Oktober</string>
+    <string name="month_long_november">November</string>
+    <string name="month_long_december">Dezember</string>
 
     <string name="month_medium_january">Jän</string>
+    <string name="month_medium_february">Feb</string>
+    <string name="month_medium_march">Mär</string>
+    <string name="month_medium_april">Apr</string>
+    <string name="month_medium_may">Mai</string>
+    <string name="month_medium_june">Jun</string>
+    <string name="month_medium_july">Jul</string>
+    <string name="month_medium_august">Aug</string>
+    <string name="month_medium_september">Sep</string>
+    <string name="month_medium_october">Okt</string>
+    <string name="month_medium_november">Nov</string>
+    <string name="month_medium_december">Dez</string>
 
     <string name="month_shortest_january">J</string>
     <string name="month_shortest_february">F</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 23ab573..d070107 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1998,6 +1998,16 @@
             <!-- The dropdown should fit the width of its anchor. -->
             <enum name="wrap_content" value="-2" />
         </attr>
+        <!-- Specifies the basic width of the dropdown. Its value may
+             be a dimension (such as "12dip") for a constant width, fill_parent
+             to fill the width of the screen, or wrap_content to match the height of
+             the content of the drop down. -->
+        <attr name="dropDownHeight" format="dimension">
+            <!-- The dropdown should fill the width of the screen. -->
+            <enum name="fill_parent" value="-1" />
+            <!-- The dropdown should fit the width of its anchor. -->
+            <enum name="wrap_content" value="-2" />
+        </attr>
         <attr name="inputType" />
     </declare-styleable>
     <declare-styleable name="PopupWindow">
@@ -2317,6 +2327,15 @@
         <attr name="drawable" />
     </declare-styleable>
 
+    <declare-styleable name="AnimatedRotateDrawable">
+        <attr name="visible" />
+        <attr name="frameDuration" format="integer" />
+        <attr name="framesCount" format="integer" />
+        <attr name="pivotX" />
+        <attr name="pivotY" />
+        <attr name="drawable" />
+    </declare-styleable>
+    
     <declare-styleable name="InsetDrawable">
         <attr name="visible" />
         <attr name="drawable" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 91cd9fd..7571e24 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -512,6 +512,9 @@
         <!-- The screen orientation has changed, that is the user has
              rotated the device. -->
         <flag name="orientation" value="0x0080" />
+        <!-- The screen orientation has changed, that is the user has
+             rotated the device. -->
+        <flag name="screenLayout" value="0x0100" />
         <!-- The font scaling factor has changed, that is the user has
              selected a new global font size. -->
         <flag name="fontScale" value="0x40000000" />
@@ -829,8 +832,59 @@
          <p>This appears as a child tag of the
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestSupportsDensity" parent="AndroidManifest">
-        <!-- Required value of the density in dip (device independent pixel). -->
-        <attr name="density" format="integer" />
+        <!-- Required value of the density in dip (device independent pixel).
+             You should use one of the pre-defined constants for the standard
+             screen densities defined here.
+        -->
+        <attr name="density" format="integer">
+            <!-- A low density screen, such as a QVGA or WQVGA screen in a
+                 typical hand-held phone.  The constant for this is 120. -->
+            <enum name="low" value="120" />
+            <!-- A medium density screen, such as an HVGA screen in a
+                 typical hand-held phone.  The constant for this is 160. -->
+            <enum name="medium" value="160" />
+            <!-- A high density screen, such as a VGA or WVGA screen in a
+                 typical hand-held phone.  The constant for this is 240. -->
+            <enum name="high" value="240" />
+        </attr>
+    </declare-styleable>
+
+    <!-- The <code>supports-screens</code> specifies the screen dimensions an
+         application supports.  By default a modern application supports all
+         screen sizes and must explicitly disable certain screen sizes here;
+         older applications are assumed to only support the traditional normal
+         (HVGA) screen size.  Note that screen size is a separate axis from
+         density, and is determined as the available pixels to an application
+         after density scaling has been applied.
+         
+         <p>This appears as a child tag of the
+         {@link #AndroidManifest manifest} tag. -->
+    <declare-styleable name="AndroidManifestSupportsScreens" parent="AndroidManifest">
+        <!-- Indicates whether the application supports smaller screen form-factors.
+             A small screen is defined as one with a smaller aspect ratio than
+             the traditional HVGA screen; that is, for a portrait screen, less
+             tall than an HVGA screen.  In practice, this means a QVGA low
+             density or VGA high density screen.  An application that does
+             not support small screens <em>will not be available</em> for
+             small screen devices, since there is little the platform can do
+             to make such an application work on a smaller screen. -->
+        <attr name="smallScreens" format="boolean" />
+        <!-- Indicates whether an application supports the normal screen
+             form-factors.  Traditionally this is an HVGA normal density
+             screen, but WQVGA low density and WVGA high density are also
+             considered to be normal.  This attribute is true by default,
+             and applications currently should leave it that way. -->
+        <attr name="normalScreens" format="boolean" />
+        <!-- Indicates whether the application supports larger screen form-factors.
+             A large screen is defined as a screen that is significantly larger
+             than a normal phone screen, and thus may require some special care
+             on the application's part to make good use of it.  An example would
+             be a VGA <em>normal density</em> screen, though even larger screens
+             are certainly possible.  An application that does not support
+             large screens will be placed as a postage stamp on such a
+             screen, so that it retains the dimensions it was originally
+             designed for. -->
+        <attr name="largeScreens" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>expandable</code> specifies if this package supports screen metrics
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e5a58b1..14d8dbe 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1116,7 +1116,11 @@
   <public type="attr" name="allowBackup" />
   <public type="attr" name="glEsVersion" />
   <public type="attr" name="queryAfterZeroResults" />
-  
+  <public type="attr" name="dropDownHeight" />
+  <public type="attr" name="smallScreens" />
+  <public type="attr" name="normalScreens" />
+  <public type="attr" name="largeScreens" />
+
   <public-padding type="attr" name="donut_resource_pad" end="0x0101029f" />
 
   <public-padding type="id" name="donut_resource_pad" end="0x01020040" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f742ab7..9f1ed40 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1804,15 +1804,15 @@
     <!-- External media notification strings -->
     <!-- Shown when external media is being checked -->
     <string name="ext_media_checking_notification_title">Preparing SD card</string>
-    <string name="ext_media_checking_notification_message">Checking for errors</string>
+    <string name="ext_media_checking_notification_message">Checking for errors.</string>
 
     <!-- Shown when external media is blank (or unsupported filesystem) -->
     <string name="ext_media_nofs_notification_title">Blank SD card</string>
-    <string name="ext_media_nofs_notification_message">The SD card is blank or using an unsupported filesystem.</string>
+    <string name="ext_media_nofs_notification_message">SD card blank or has unsupported filesystem.</string>
 
     <!-- Shown when external media is unmountable (corrupt)) -->
     <string name="ext_media_unmountable_notification_title">Damaged SD card</string>
-    <string name="ext_media_unmountable_notification_message">The SD card is damaged. You may have to reformat your card.</string>
+    <string name="ext_media_unmountable_notification_message">SD card damaged. You may have to reformat it.</string>
 
     <!-- Shown when external media is unsafely removed -->
     <string name="ext_media_badremoval_notification_title">SD card unexpectedly removed</string>
@@ -1820,11 +1820,11 @@
 
     <!-- Shown when external media has been safely removed -->
     <string name="ext_media_safe_unmount_notification_title">SD card safe to remove</string>
-    <string name="ext_media_safe_unmount_notification_message">The SD card can now be safely removed.</string>
+    <string name="ext_media_safe_unmount_notification_message">You can safely remove SD card.</string>
 
     <!-- Shown when external media is missing -->
     <string name="ext_media_nomedia_notification_title">Removed SD card</string>
-    <string name="ext_media_nomedia_notification_message">The SD has been removed. Insert a new SD card to increase your device storage.</string>
+    <string name="ext_media_nomedia_notification_message">SD card removed. Insert a new one.</string>
 
     <!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
     <string name="activity_list_empty">No matching activities found</string>
diff --git a/docs/html/guide/topics/resources/res-selection-flowchart.png b/docs/html/guide/topics/resources/res-selection-flowchart.png
new file mode 100755
index 0000000..d738b3f0
--- /dev/null
+++ b/docs/html/guide/topics/resources/res-selection-flowchart.png
Binary files differ
diff --git a/docs/html/guide/topics/resources/res-selection-flowchart.vsd b/docs/html/guide/topics/resources/res-selection-flowchart.vsd
new file mode 100755
index 0000000..65bfcdb
--- /dev/null
+++ b/docs/html/guide/topics/resources/res-selection-flowchart.vsd
Binary files differ
diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd
old mode 100644
new mode 100755
index 4bbb44a..6900704
--- a/docs/html/guide/topics/resources/resources-i18n.jd
+++ b/docs/html/guide/topics/resources/resources-i18n.jd
@@ -1,713 +1,716 @@
-page.title=Resources and Internationalization
-parent.title=Resources and Assets
-parent.link=index.html
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-  <h2>Key classes</h2>
-  <ol>
-    <li>{@link android.content.res.Resources}</li>
-  </ol>
-
-  <h2>In this document</h2>
-  <ol>
-    <li><a href="#intro">Introduction</a></li>
-    <li><a href="#CreatingResources">Creating Resources</a></li>
-    <li><a href="#UsingResources">Using Resources</a>
-      <ol>
-        <li><a href="#ResourcesInCode">Using Resources in Code</a></li>
-        <li><a href="#ReferencesToResources">References to Resources</a></li>
-        <li><a href="#ReferencesToThemeAttributes">References to Theme Attributes</a></li>
-        <li><a href="#UsingSystemResources">Using System Resources</a></li>
-      </ol>
-    </li>
-    <li><a href="#AlternateResources">Alternate Resources</a></li>
-    <li><a href="#ResourcesTerminology">Terminology</a></li>
-    <li><a href="#i18n">Internationalization (I18N)</a></li>
-  </ol>
-</div>
-</div>
-
-<p>Resources are external files (that is, non-code files) that are used by
-your code and compiled into your application at build time. Android
-supports a number of different kinds of resource files, including XML,
-PNG, and JPEG files. The XML files have very different formats depending
-on what they describe. This document describes what kinds of files are
-supported, and the syntax or format of each.</p>
-<p>Resources are externalized from source code, and XML files are compiled into
-a binary, fast loading format for efficiency reasons. Strings, likewise are compressed
-into a more efficient storage form. It is for these reasons that we have these
-different resource types in the Android platform.</p>
-
-<p>This is a fairly technically dense document, and together with the
-<a href="available-resources.html">Available Resources</a>
-document, they cover a lot of information about resources. It is not necessary
-to know this document by heart to use Android, but rather to know that the
-information is here when you need it.</p>
-
-<a name="intro"></a>
-<h2>Introduction</h2>
-
-<p>This topic includes a terminology list associated with resources, and a series
-    of examples of using resources in code. For a complete guide to the supported 
-    Android resource types, see 
-    <a href="available-resources.html">Available Resources</a>.
-    </p>
-<p>The Android resource system keeps track of all non-code
-    assets associated with an application.  You use the
-    {@link android.content.res.Resources Resources} class to access your
-    application's resources; the Resources instance associated with your
-    application can generally be found through
-    {@link android.content.Context#getResources Context.getResources()}.</p>
-<p>An application's resources are compiled into the application
-binary at build time for you by the build system.  To use a resource,
-you must install it correctly in the source tree and build your
-application.  As part of the build process, symbols for each
-of the resources are generated that you can use in your source
-code -- this allows the compiler to verify that your application code matches
-up with the resources you defined.</p>
-
-<p>The rest of this section is organized as a tutorial on how to
-use resources in an application.</p>
-
-<a name="CreatingResources" id="CreatingResources"></a>
-<h2>Creating Resources</h2>
-
-<p>Android supports string, bitmap, and many other types of resource. The syntax and format
-of each, and where they're stored, depends upon the type of object. In
-general, though, you create resources from three types of files: XML files
-(everything but bitmaps and raw), bitmap files(for images) and Raw files (anything
-else, for example sound files, etc.). In fact, there are two different types of
-XML file as well, those that get compiled as-is into the package, and those that
-are used to generate resources by aapt. Here is a list of each
-resource type, the format of the file, a description of the file, and details
-of any XML files. </p>
-
-<p>You will create and store your resource files under the appropriate
-subdirectory under the <code>res/</code> directory in your project. Android
-has a resource compiler (aapt) that compiles resources according to which
-subfolder they are in, and the format of the file. Here is a list of the file
-types for each resource. See the 
-<a href="available-resources.html">Available Resources</a> for
-descriptions of each type of object, the syntax, and the format or syntax of
-the containing file.</p>
-
-<table width="100%" border="1">
-    <tr>
-        <th scope="col">Directory</th>
-        <th scope="col">Resource Types </th>
-    </tr>
-    <tr>
-        <td><code>res/anim/</code></td>
-        <td>XML files that are compiled into 
-        <a href="available-resources.html#animationdrawable">frame by
-        frame animation</a> or 
-        <a href="available-resources.html#tweenedanimation">tweened
-        animation</a> objects </td>
-    </tr>
-    <tr>
-        <td><code>res/drawable/</code></td>
-        <td><p>.png, .9.png, .jpg files that are compiled into the following
-                Drawable resource subtypes:</p>
-            <ul class="nolist">
-                <li><a href="available-resources.html#imagefileresources">bitmap files</a></li>
-                <li><a href="available-resources.html#ninepatch">9-patches (resizable bitmaps)</a></li>
-            </ul>
-            <p>To get a resource of this type, use <code>mContext.getResources().getDrawable(R.drawable.<em>imageId</em>)</code></p>
-            <p class="note"><strong>Note:</strong> Image resources placed in here may 
-              be automatically optimized with lossless image compression by the 
-              <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For example, a true-color PNG 
-              that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette.
-              This will result in an image of equal quality but which requires less memory. So be aware that the
-              image binaries placed in this directory can change during the build. If you plan on reading
-              an image as a bit stream in order to convert it to a bitmap, put your images in the 
-              <code>res/raw/</code> folder instead, where they will not be optimized.</p>
-        </td>
-    </tr>
-    <tr>
-        <td><code>res/layout/</code></td>
-        <td>XML files that are compiled into screen layouts (or part of a screen).
-            See <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>.</td>
-    </tr>
-    <tr>
-        <td><code>res/values/</code></td>
-        <td><p>XML files that can be compiled into many kinds of resource.</p>
-            <p class="note"><strong>Note:</strong> Unlike the other res/ folders, this one
-            can hold any number of files that hold descriptions of resources to create
-            rather than the resources themselves. The XML element types control
-            where these resources are placed under the R class.</p>
-            <p>While the files can be named anything, these are
-                the typical files in this folder (the convention is to name
-                the file after the type of elements defined within):</p>
-            <ul>
-                <li><strong>arrays.xml</strong> to define arrays </li>  
-                <!-- TODO: add section on arrays -->
-                <li><strong>colors.xml</strong> to define <a href="available-resources.html#colordrawableresources">color
-                        drawables</a> and <a  href="#colorvals">color string values</a>.
-                        Use <code>Resources.getDrawable()</code> and
-                        <code>Resources.getColor(), respectively,</code>
-                to get these resources.</li>
-                <li><strong>dimens.xml</strong> to define <a href="available-resources.html#dimension">dimension value</a>. Use <code>Resources.getDimension()</code> to get
-                these resources.</li>
-                <li><strong>strings.xml</strong> to define <a href="available-resources.html#stringresources">string</a> values (use either         
-                <code>Resources.getString</code> or preferably <code>Resources.getText()</code>
-                to get
-                these resources. <code>getText()</code> will retain any rich text styling
-                which is usually desirable for UI strings.</li>
-                <li><strong>styles.xml</strong> to define <a href="available-resources.html#stylesandthemes">style</a> objects.</li>
-            </ul></td>
-    </tr>
-    <tr>
-        <td><code>res/xml/</code></td>
-        <td>Arbitrary XML files that are compiled and can be read at run time by
-            calling {@link android.content.res.Resources#getXml(int) Resources.getXML()}.</td>
-    </tr>
-    <tr>
-        <td><code>res/raw/</code></td>
-        <td>Arbitrary files to copy directly to the device. They are added uncompiled
-            to the compressed file that your application build produces. To use these
-            resources in your application, call {@link android.content.res.Resources#openRawResource(int)
-            Resources.openRawResource()} with the resource ID, which is R.raw.<em>somefilename</em>.</td>
-    </tr>
-</table>
-<p>Resources are compiled into the final APK file. Android creates a wrapper class,
-    called R, that you can use to refer to these resources in your code. R contains subclasses
-    named according to the path and file name of the source file</p>
-<a name="colorvals" id="colorvals"></a>
-<h3>Global Resource Notes</h3>
-<ul>
-    <li>Several resources allow you to define colors. Android accepts color values
-        written in various web-style formats -- a hexadecimal constant in any of the
-        following forms: #RGB, #ARGB, #RRGGBB, #AARRGGBB. </li>
-    <li>All color values support setting an alpha channel value, where the first
-        two hexadecimal numbers specify the transparency. Zero in the alpha channel
-        means transparent. The default value is opaque. </li>
-</ul>
-<a name="UsingResources" id="UsingResources"></a>
-<h2>Using Resources </h2>
-<p>This section describes how to use the resources you've created. It includes the
-    following topics:</p>
-<ul>
-    <li><a href="#ResourcesInCode">Using resources in code</a>&nbsp;- How to call
-        resources in your code to instantiate them. </li>
-    <li><a href="#ReferencesToResources">Referring to resources from other resources</a> &nbsp;-
-        You can reference resources from other resources. This lets you reuse common 
-        resource values inside resources. </li>
-    <li><a href="#AlternateResources">Supporting Alternate Resources for Alternate
-            Configurations</a> - You can specify different resources
-            to load, depending on the language or display configuration of the host
-            hardware. </li>
-</ul>
-<p>At compile time, Android generates a class named R that contains resource identifiers
-    to all the resources in your program. This class contains several subclasses,
-    one for each type of resource supported by Android, and for which you provided
-    a resource file. Each class contains one or more identifiers for the compiled resources,
-    that you use in your code to load the resource. Here is a small resource file
-    that contains string, layout (screens or parts of screens), and image resources.</p>
-<p class="note"><strong>Note:</strong> the R class is an auto-generated file and is not
-designed to be edited by hand. It will be automatically re-created as needed when
-the resources are updated.</p>
-<pre class="prettyprint">package com.android.samples;
-public final class R {
-    public static final class string {
-        public static final int greeting=0x0204000e;
-        public static final int start_button_text=0x02040001;
-        public static final int submit_button_text=0x02040008;
-        public static final int main_screen_title=0x0204000a;
-    };
-    public static final class layout {
-        public static final int start_screen=0x02070000;
-        public static final int new_user_pane=0x02070001;
-        public static final int select_user_list=0x02070002;
-
-    };
-    public static final class drawable {
-        public static final int company_logo=0x02020005;
-        public static final int smiling_cat=0x02020006;
-        public static final int yellow_fade_background=0x02020007;
-        public static final int stretch_button_1=0x02020008;
-
-    };
-};
-</pre>
-<a name="ResourcesInCode" id="ResourcesInCode"></a>
-<h3>Using Resources in Code </h3>
-
-<p>Using resources in code is just a matter of knowing the full resource ID
-and what type of object your resource has been compiled into. Here is the
-syntax for referring to a resource:</p>
-<p><code>R.<em>resource_type</em>.<em>resource_name</em></code></p>
-<p>or</p>
-<p><code>android.R.<em>resource_type</em>.<em>resource_name</em></code></p>
-
-<p>Where <code>resource_type</code> is the R subclass that holds a specific type
-of resource. <code>resource_name</code> is the <em>name</em> attribute for resources
-defined in XML files, or the file name (without the extension) for resources
-defined by other file types. Each type of resource will be added to a specific
-R subclass, depending on the type of resource it is; to learn which R subclass
-hosts your compiled resource type, consult the 
-<a href="available-resources.html">Available Resources</a> document. Resources compiled by your own application can
-be referred to without a package name (simply as
-<code>R.<em>resource_type</em>.<em>resource_name</em></code>). Android contains
-a number of standard resources, such as screen styles and button backgrounds. To
-refer to these in code, you must qualify them with <code>android</code>, as in
-<code>android.R.drawable.button_background</code>.</p>
-
-<p>Here are some good and bad examples of using compiled resources in code:</p>
-
-<pre class="prettyprint">// Load a background for the current screen from a drawable resource.
-this.getWindow().setBackgroundDrawableResource(R.drawable.my_background_image);
-
-// WRONG Sending a string resource reference into a 
-// method that expects a string.
-this.getWindow().setTitle(R.string.main_title);
-
-// RIGHT Need to get the title from the Resources wrapper.
-this.getWindow().setTitle(Resources.getText(R.string.main_title));
-
-// Load a custom layout for the current screen.
-setContentView(R.layout.main_screen);
-
-// Set a slide in animation for a ViewFlipper object.
-mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, 
-        R.anim.hyperspace_in));
-
-// Set the text on a TextView object.
-TextView msgTextView = (TextView)findViewByID(R.id.msg);
-msgTextView.setText(R.string.hello_message); </pre>
-
-<a name="ReferencesToResources" id="ReferencesToResources"></a>
-<h3>References to Resources</h3>
-
-<p>A value supplied in an attribute (or resource) can also be a reference to
-a resource.  This is often used in layout files to supply strings (so they
-can be localized) and images (which exist in another file), though a reference
-can be any resource type including colors and integers.</p>
-
-<p>For example, if we have 
-<a href="available-resources.html#colordrawableresources">color 
-resources</a>, we can write a layout file that sets the text color size to be
-the value contained in one of those resources:</p>
-
-<pre>
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;EditText id=&quot;text&quot;
-    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
-    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;
-    <strong>android:textColor=&quot;&#64;color/opaque_red&quot;</strong>
-    android:text=&quot;Hello, World!&quot; /&gt;
-</pre>
-
-<p>Note here the use of the '@' prefix to introduce a resource reference -- the
-text following that is the name of a resource in the form
-of <code>@[package:]type/name</code>.  In this case we didn't need to specify
-the package because we are referencing a resource in our own package.  To
-reference a system resource, you would need to write:</p>
-
-<pre>
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;EditText id=&quot;text&quot;
-    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
-    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;
-    android:textColor=&quot;&#64;<strong>android:</strong>color/opaque_red&quot;
-    android:text=&quot;Hello, World!&quot; /&gt;
-</pre>
-
-<p>As another example, you should always use resource references when supplying
-strings in a layout file so that they can be localized:</p>
-
-<pre>
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;EditText id=&quot;text&quot;
-    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
-    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;
-    android:textColor=&quot;&#64;android:color/opaque_red&quot;
-    android:text=&quot;&#64;string/hello_world&quot; /&gt;
-</pre>
-
-<p>This facility can also be used to create references between resources.
-For example, we can create new drawable resources that are aliases for
-existing images:</p>
-
-<pre>
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;resources&gt;
-    &lt;drawable id=&quot;my_background&quot;&gt;&#64;android:drawable/theme2_background&lt;/drawable&gt;
-&lt;/resources&gt;
-</pre>
-
-<a name="ReferencesToThemeAttributes"></a>
-<h3>References to Theme Attributes</h3>
-
-<p>Another kind of resource value allows you to reference the value of an
-attribute in the current theme.  This attribute reference can <em>only</em>
-be used in style resources and XML attributes; it allows you to customize the
-look of UI elements by changing them to standard variations supplied by the
-current theme, instead of supplying more concrete values.</p>
-
-<p>As an example, we can use this in our layout to set the text color to
-one of the standard colors defined in the base system theme:</p>
-
-<pre>
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;EditText id=&quot;text&quot;
-    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
-    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;
-    <strong>android:textColor=&quot;?android:textDisabledColor&quot;</strong>
-    android:text=&quot;&#64;string/hello_world&quot; /&gt;
-</pre>
-
-<p>Note that this is very similar to a resource reference, except we are using
-an '?' prefix instead of '@'.  When you use this markup, you are supplying
-the name of an attribute resource that will be looked up in the theme --
-because the resource tool knows that an attribute resource is expected,
-you do not need to explicitly state the type (which would be
-<code>?android:attr/android:textDisabledColor</code>).</p>
-
-<p>Other than using this resource identifier to find the value in the
-theme instead of raw resources, the name syntax is identical to the '@' format:
-<code>?[namespace:]type/name</code> with the type here being optional.</p>
-
-<a name="UsingSystemResources"></a>
-<h3>Using System Resources</h3>
-
-<p>Many resources included with the system are available to applications.
-All such resources are defined under the class "android.R".  For example,
-you can display the standard application icon in a screen with the following
-code:</p>
-
-<pre class="prettyprint">
-public class MyActivity extends Activity
-{
-    public void onStart() 
-    {
-        requestScreenFeatures(FEATURE_BADGE_IMAGE);
-
-        super.onStart();
-
-        setBadgeResource(android.R.drawable.sym_def_app_icon);
-    }
-}
-</pre>
-
-<p>In a similar way, this code will apply to your screen the standard
-"green background" visual treatment defined by the system:</p>
-
-<pre class="prettyprint">
-public class MyActivity extends Activity
-{
-    public void onStart() 
-    {
-        super.onStart();
-
-        setTheme(android.R.style.Theme_Black);
-    }
-}
-</pre>
-
-<a name="AlternateResources" id="AlternateResources"></a>
-<h2>Alternate Resources (for alternate languages and configurations)</h2>
-
-<p>You can supply different resources for your product according to the UI
-language or hardware configuration on the device. Note that although you can
-include different string, layout, and other resources, the SDK does not expose
-methods to let you specify which alternate resource set to load. Android
-detects the proper set for the hardware and location, and loads them as
-appropriate. Users can select alternate language settings using the settings
-panel on the device. </p>
-<p>To include alternate resources, create parallel resource folders with
-qualifiers appended to the folder names, indicating the configuration it
-applies to (language, screen orientation, and so on). For example, here is a
-project that holds one string resource file for English, and another for
-French:</p>
-
-<pre>
-MyApp/
-    res/
-        values-en/
-            strings.xml
-        values-fr/
-            strings.xml
-</pre>
-
-<p>Android supports several types of qualifiers, with various values for each.
-Append these to the end of the resource folder name, separated by dashes. You
-can add multiple qualifiers to each folder name, but they must appear in the
-order they are listed here. For example, a folder containing drawable
-resources for a fully specified configuration would look like:</p>
-
-<pre>
-MyApp/
-    res/
-        drawable-en-rUS-port-160dpi-finger-keysexposed-qwerty-dpad-480x320/
-</pre>
-
-<p>More typically, you will only specify a few specific configuration options
-that a resource is defined for. You may drop any of the values from the
-complete list, as long as the remaining values are still in the same
-order:</p>
-
-<pre>
-MyApp/
-    res/
-        drawable-en-rUS-finger/
-        drawable-port/
-        drawable-port-160dpi/
-        drawable-qwerty/
-</pre>
-
-<table border="1">
-    <tr>
-        <th> Qualifier </th>
-        <th> Values </th>
-    </tr>
-    <tr>
-        <td>Language</td>
-        <td>The two letter <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO
-                639-1</a> language code in lowercase. For example: 
-                <code>en</code>, <code>fr</code>, <code>es</code> </td>
-    </tr>
-    <tr>
-        <td>Region</td>
-        <td>The two letter
-        <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO
-                3166-1-alpha-2</a> language code in uppercase preceded by a lowercase
-            &quot;r&quot;. For example: <code>rUS</code>, <code>rFR</code>, <code>rES</code></td>
-    </tr>
-    <tr>
-        <td>Screen orientation</td>
-        <td><code>port</code>, <code>land</code>, <code>square</code> </td>
-    </tr>
-    <tr>
-        <td>Screen pixel density</td>
-        <td><code>92dpi</code>, <code>108dpi</code>, etc. </td>
-    </tr>
-    <tr>
-        <td>Touchscreen type</td>
-        <td><code>notouch</code>, <code>stylus</code>, <code>finger</code></td>
-    </tr>
-    <tr>
-        <td>Whether the keyboard is available to the user</td>
-        <td><code>keysexposed</code>, <code>keyshidden</code> </td>
-    </tr>
-    <tr>
-        <td>Primary text input method</td>
-        <td><code>nokeys</code>, <code>qwerty</code>, <code>12key</code> </td>
-    </tr>
-    <tr>
-        <td>Primary non-touchscreen<br />
-            navigation method</td>
-        <td><code>nonav</code>, <code>dpad</code>, <code>trackball</code>, <code>wheel</code> </td>
-    </tr>
-    <tr>
-        <td>Screen dimensions</td>
-        <td><code>320x240</code>, <code>640x480</code>, etc. The larger dimension
-            must be specified first. </td>
-    </tr>
-</table>
-
-<p>This list does not include device-specific parameters such as carrier,
-branding, device/hardware, or manufacturer. Everything that an application
-needs to know about the device that it is running on is encoded via the
-resource qualifiers in the table above.</p>
-
-<p>Here are some general guidelines on qualified resource directory names:</p>
-
-<ul>
-    <li>Values are separated by a dash (as well as a dash after the base directory
-        name) </li>
-    <li>Values are case-sensitive (even though they must be unique across all folder
-        names in a case-insensitive way)<br />For example,</li>
-    <ul>
-        <li>A portrait-specific <code>drawable</code> directory must be named
-            <code>drawable-port</code>, not <code>drawable-PORT</code>.</li>
-        <li>You may not have two directories named <code>drawable-port</code>
-            and <code>drawable-PORT</code>, even if you had intended "port" and
-            "PORT" to refer to different parameter values.</li>
-    </ul>
-    <li>Only one value for each qualifier type is supported (that is, you cannot
-        specify <code>drawable-rEN-rFR/</code>)</li>
-    <li>You can specify multiple parameters to define specific configurations,
-        but they must always be in the order listed above.
-        For example, <code>drawable-en-rUS-land</code> will apply to landscape view,
-        US-English devices. </li>
-    <li>Android will try to find the most specific matching directory for the current
-        configuration, as described below</li>
-    <li>The order of parameters listed in this table is used to break a tie in case
-        of multiple qualified directories (see the example given below) </li>
-    <li>All directories, both qualified and unqualified, live under the <code>res/</code> folder.
-        Qualified directories cannot be nested (you cannot have <code>res/drawable/drawable-en</code>) </li>
-    <li>All resources will be referenced in code or resource reference syntax by
-        their simple, undecorated name. So if a resource is named this:<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>MyApp/res/drawable-port-92dp/myimage.png</code><br />
-        It would be referenced as this:<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>R.drawable.myimage</code> (code)<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>&#064;drawable/myimage</code> (XML)</li>
-</ul>
-
-<h3>How Android finds the best matching directory </h3>
-
-<p>Android will pick which of the various underlying resource files should be
-used at runtime, depending on the current configuration. The selection process
-is as follows:</p>
-
-<ol>
-    <li>
-            Eliminate any resources whose configuration does not match the current
-            device configuration. For example, if the screen pixel density is 108dpi,
-            this would eliminate only <code>MyApp/res/drawable-port-92dpi/</code>.
-        <blockquote>
-            <pre>
-MyApp/res/drawable/myimage.png
-MyApp/res/drawable-en/myimage.png
-MyApp/res/drawable-port/myimage.png
-<strike>MyApp/res/drawable-port-92dpi/myimage.png</strike>
-</pre>
-        </blockquote>
-    </li>
-    <li>
-            Pick the resources with the highest number of matching configurations.
-            For example, if our locale is en-GB and orientation is port, then we
-            have two candidates with one matching configuration each: 
-            <code>MyApp/res/drawable-en/</code> and <code>MyApp/res/drawable-port/</code>.
-            The directory <code>MyApp/res/drawable/</code> is eliminated because
-            it has zero matching configurations, while the others have one matching
-            configuration.
-        <blockquote>
-            <pre>
-<strike>MyApp/res/drawable/myimage.png</strike>
-MyApp/res/drawable-en/myimage.png
-MyApp/res/drawable-port/myimage.png
-</pre>
-        </blockquote>
-    </li>
-    <li>
-            Pick the final matching file based on configuration precedence, which
-            is the order of parameters listed in the table above. That is, it is
-            more important to match the language than the orientation, so we break
-            the tie by picking the language-specific file, <code>MyApp/res/drawable-en/</code>.
-        <blockquote>
-            <pre>MyApp/res/drawable-en/myimage.png
-<strike>MyApp/res/drawable-port/myimage.png</strike>
-</pre>
-        </blockquote>
-    </li>
-</ol>
-
-<a name="ResourcesTerminology"></a>
-<h2>Terminology</h2>
-
-<p>The resource system brings a number of different pieces together to
-form the final complete resource functionality.  To help understand the
-overall system, here are some brief definitions of the core concepts and
-components you will encounter in using it:</p>
-
-<p><strong>Asset</strong>: A single blob of data associated with an application. This
-includes object files compiled from the Java source code, graphics (such as PNG
-images), XML files, etc. These files are organized in a directory hierarchy
-that, during final packaging of the application, is bundled together into a
-single ZIP file.</p>
-
-<p><strong>aapt</strong>: Android Asset Packaging Tool. The tool that generates the 
-final ZIP file of application assets.  In addition to collecting raw assets 
-together, it also parses resource definitions into binary asset data.</p>
-
-<p><strong>Resource Table</strong>: A special asset that aapt generates for you,
-describing all of the resources contained in an application/package.
-This file is accessed for you by the Resources class; it is not touched
-directly by applications.</p>
-
-<p><strong>Resource</strong>: An entry in the Resource Table describing a single
-named value.  Broadly, there are two types of resources: primitives and
-bags.</p>
-
-<p><strong>Resource Identifier</strong>: In the Resource Table all resources are
-identified by a unique integer number.  In source code (resource descriptions,
-XML files, Java source code) you can use symbolic names that stand as constants for
-the actual resource identifier integer.</p>
-
-<p><strong>Primitive Resource</strong>: All primitive resources can be written as a
-simple string, using formatting to describe a variety of primitive types
-included in the resource system: integers, colors, strings, references to
-other resources, etc.  Complex resources, such as bitmaps and XML
-describes, are stored as a primitive string resource whose value is the path
-of the underlying Asset holding its actual data.</p>
-
-<p><strong>Bag Resource</strong>: A special kind of resource entry that, instead of a
-simple string, holds an arbitrary list of name/value pairs.  Each name is
-itself a resource identifier, and each value can hold
-the same kinds of string formatted data as a normal resource.  Bags also
-support inheritance: a bag can inherit the values from another bag, selectively
-replacing or extending them to generate its own contents.</p>
-
-<p><strong>Kind</strong>: The resource kind is a way to organize resource identifiers
-for various purposes.  For example, drawable resources are used to
-instantiate Drawable objects, so their data is a primitive resource containing
-either a color constant or string path to a bitmap or XML asset.  Other
-common resource kinds are string (localized string primitives), color
-(color primitives), layout (a string path to an XML asset describing a view
-layout), and style (a bag resource describing user interface attributes).
-There is also a standard "attr" resource kind, which defines the resource
-identifiers to be used for naming bag items and XML attributes</p>
-
-<p><strong>Style</strong>: The name of the resource kind containing bags that are used
-to supply a set of user interface attributes.  For example, a TextView class may
-be given a style resource that defines its text size, color, and alignment.
-In a layout XML file, you associate a style with a bag using the "style"
-attribute, whose value is the name of the style resource.</p>
-
-<p><strong>Style Class</strong>: Specifies a related set of attribute resources.
-This data is not placed in the resource table itself, but used to generate
-constants in the source code that make it easier for you to retrieve values out of
-a style resource and/or XML tag's attributes.  For example, the
-Android platform defines a "View" style class that
-contains all of the standard view attributes: padding, visibility,
-background, etc.; when View is inflated it uses this style class to
-retrieve those values from the XML file (at which point style and theme
-information is applied as approriate) and load them into its instance.</p>
-
-<p><strong>Configuration</strong>: For any particular resource identifier, there may be
-multiple different available values depending on the current configuration.
-The configuration includes the locale (language and country), screen
-orientation, screen density, etc.  The current configuration is used to
-select which resource values are in effect when the resource table is
-loaded.</p>
-
-<p><strong>Theme</strong>: A standard style resource that supplies global
-attribute values for a particular context.  For example, when writing an
-Activity the application developer can select a standard theme to use, such
-as the Theme.White or Theme.Black styles; this style supplies information
-such as the screen background image/color, default text color, button style,
-text editor style, text size, etc.  When inflating a layout resource, most
-values for widgets (the text color, selector, background) if not explicitly
-set will come from the current theme; style and attribute
-values supplied in the layout can also assign their value from explicitly
-named values in the theme attributes if desired.</p>
-
-<p><strong>Overlay</strong>: A resource table that does not define a new set of resources,
-but instead replaces the values of resources that are in another resource table.
-Like a configuration, this is applied at load time
-to the resource data; it can add new configuration values (for example
-strings in a new locale), replace existing values (for example change
-the standard white background image to a "Hello Kitty" background image),
-and modify resource bags (for example change the font size of the Theme.White
-style to have an 18 pt font size).  This is the facility that allows the
-user to select between different global appearances of their device, or
-download files with new appearances.</p>
-
-<h2>Resource Reference</h2>
-<p>The <a href="available-resources.html">Available Resources</a>
-document provides a detailed list of the various types of resource and how to use them
-from within the Java source code, or from other references.</p>
-
-<a name="i18n" id="i18n"></a>
-<h2>Internationalization and Localization</h2>
-<p class="note"><strong>Coming Soon:</strong> Internationalization and Localization are
-critical, but are also not quite ready yet in the current SDK. As the
-SDK matures, this section will contain information on the Internationalization
-and Localization features of the Android platform. In the meantime, it is a good
-idea to start by externalizing all strings, and practicing good structure in
-creating and using resources.</p>
-
+page.title=Resources and Internationalization

+parent.title=Resources and Assets

+parent.link=index.html

+@jd:body

+

+<div id="qv-wrapper">

+<div id="qv">

+

+  <h2>Key classes</h2>

+  <ol>

+    <li>{@link android.content.res.Resources}</li>

+  </ol>

+

+  <h2>In this document</h2>

+  <ol>

+    <li><a href="#intro">Introduction</a></li>

+    <li><a href="#CreatingResources">Creating Resources</a></li>

+    <li><a href="#UsingResources">Using Resources</a>

+      <ol>

+        <li><a href="#ResourcesInCode">Using Resources in Code</a></li>

+        <li><a href="#ReferencesToResources">References to Resources</a></li>

+        <li><a href="#ReferencesToThemeAttributes">References to Theme Attributes</a></li>

+        <li><a href="#UsingSystemResources">Using System Resources</a></li>

+      </ol>

+    </li>

+    <li><a href="#AlternateResources">Alternate Resources</a></li>

+    <li><a href="#ResourcesTerminology">Terminology</a></li>

+    <li><a href="#i18n">Internationalization (I18N)</a></li>

+  </ol>

+</div>

+</div>

+

+<p>Resources are external files (that is, non-code files) that are used by

+your code and compiled into your application at build time. Android

+supports a number of different kinds of resource files, including XML,

+PNG, and JPEG files. The XML files have very different formats depending

+on what they describe. This document describes what kinds of files are

+supported, and the syntax or format of each.</p>

+<p>Resources are externalized from source code, and XML files are compiled into

+a binary, fast loading format for efficiency reasons. Strings, likewise, are compressed

+into a more efficient storage form. It is for these reasons that we have these

+different resource types in the Android platform.</p>

+

+<p>This is a fairly technically dense document, and together with the

+<a href="available-resources.html">Available Resources</a>

+document, they cover a lot of information about resources. It is not necessary

+to know this document by heart to use Android, but rather to know that the

+information is here when you need it.</p>

+

+<a name="intro"></a>

+<h2>Introduction</h2>

+

+<p>This topic includes a terminology list associated with resources, and a series

+    of examples of using resources in code. For a complete guide to the supported 

+    Android resource types, see 

+    <a href="available-resources.html">Available Resources</a>.

+    </p>

+<p>The Android resource system keeps track of all non-code

+    assets associated with an application.  You use the

+    {@link android.content.res.Resources Resources} class to access your

+    application's resources; the Resources instance associated with your

+    application can generally be found through

+    {@link android.content.Context#getResources Context.getResources()}.</p>

+<p>An application's resources are compiled into the application

+binary at build time for you by the build system.  To use a resource,

+you must install it correctly in the source tree and build your

+application.  As part of the build process, symbols for each

+of the resources are generated that you can use in your source

+code -- this allows the compiler to verify that your application code matches

+up with the resources you defined.</p>

+

+<p>The rest of this section is organized as a tutorial on how to

+use resources in an application.</p>

+

+<a name="CreatingResources" id="CreatingResources"></a>

+<h2>Creating Resources</h2>

+

+<p>Android supports string, bitmap, and many other types of resource. The syntax and format

+of each, and where they're stored, depends upon the type of object. In

+general, though, you create resources from three types of files: XML files

+(everything but bitmaps and raw), bitmap files(for images) and Raw files (anything

+else, for example sound files, etc.). In fact, there are two different types of

+XML file as well, those that get compiled as-is into the package, and those that

+are used to generate resources by aapt. Here is a list of each

+resource type, the format of the file, a description of the file, and details

+of any XML files. </p>

+

+<p>You will create and store your resource files under the appropriate

+subdirectory under the <code>res/</code> directory in your project. Android

+has a resource compiler (aapt) that compiles resources according to which

+subfolder they are in, and the format of the file. Table 1 shows a llist of the file

+types for each resource. See the 

+<a href="available-resources.html">Available Resources</a> for

+descriptions of each type of object, the syntax, and the format or syntax of

+the containing file.</p>

+<p class="caption">Table 1</p>

+<table width="100%" border="1">

+    <tr>

+        <th scope="col">Directory</th>

+        <th scope="col">Resource Types </th>

+    </tr>

+    <tr>

+        <td><code>res/anim/</code></td>

+        <td>XML files that are compiled into 

+        <a href="available-resources.html#animationdrawable">frame by

+        frame animation</a> or 

+        <a href="available-resources.html#tweenedanimation">tweened

+        animation</a> objects </td>

+    </tr>

+    <tr>

+        <td><code>res/drawable/</code></td>

+        <td><p>.png, .9.png, .jpg files that are compiled into the following

+                Drawable resource subtypes:</p>

+            <ul class="nolist">

+                <li><a href="available-resources.html#imagefileresources">bitmap files</a></li>

+                <li><a href="available-resources.html#ninepatch">9-patches (resizable bitmaps)</a></li>

+            </ul>

+            <p>To get a resource of this type, use <code>mContext.getResources().getDrawable(R.drawable.<em>imageId</em>)</code></p>

+            <p class="note"><strong>Note:</strong> Image resources placed in here may 

+              be automatically optimized with lossless image compression by the 

+              <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For example, a true-color PNG 

+              that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette.

+              This will result in an image of equal quality but which requires less memory. So be aware that the

+              image binaries placed in this directory can change during the build. If you plan on reading

+              an image as a bit stream in order to convert it to a bitmap, put your images in the 

+              <code>res/raw/</code> folder instead, where they will not be optimized.</p>

+        </td>

+    </tr>

+    <tr>

+        <td><code>res/layout/</code></td>

+        <td>XML files that are compiled into screen layouts (or part of a screen).

+            See <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>.</td>

+    </tr>

+    <tr>

+        <td><code>res/values/</code></td>

+        <td><p>XML files that can be compiled into many kinds of resource.</p>

+            <p class="note"><strong>Note:</strong> Unlike the other res/ folders, this one

+            can hold any number of files that hold descriptions of resources to create

+            rather than the resources themselves. The XML element types control

+            where these resources are placed under the R class.</p>

+            <p>While the files can be named anything, these are

+                the typical files in this folder (the convention is to name

+                the file after the type of elements defined within):</p>

+            <ul>

+                <li><strong>arrays.xml</strong> to define arrays </li>  

+                <!-- TODO: add section on arrays -->

+                <li><strong>colors.xml</strong> to define <a href="available-resources.html#colordrawableresources">color

+                        drawables</a> and <a  href="#colorvals">color string values</a>.

+                        Use <code>Resources.getDrawable()</code> and

+                        <code>Resources.getColor(), respectively,</code>

+                to get these resources.</li>

+                <li><strong>dimens.xml</strong> to define <a href="available-resources.html#dimension">dimension value</a>. Use <code>Resources.getDimension()</code> to get

+                these resources.</li>

+                <li><strong>strings.xml</strong> to define <a href="available-resources.html#stringresources">string</a> values (use either         

+                <code>Resources.getString</code> or preferably <code>Resources.getText()</code>

+                to get

+                these resources. <code>getText()</code> will retain any rich text styling

+                which is usually desirable for UI strings.</li>

+                <li><strong>styles.xml</strong> to define <a href="available-resources.html#stylesandthemes">style</a> objects.</li>

+            </ul></td>

+    </tr>

+    <tr>

+        <td><code>res/xml/</code></td>

+        <td>Arbitrary XML files that are compiled and can be read at run time by

+            calling {@link android.content.res.Resources#getXml(int) Resources.getXML()}.</td>

+    </tr>

+    <tr>

+        <td><code>res/raw/</code></td>

+        <td>Arbitrary files to copy directly to the device. They are added uncompiled

+            to the compressed file that your application build produces. To use these

+            resources in your application, call {@link android.content.res.Resources#openRawResource(int)

+            Resources.openRawResource()} with the resource ID, which is R.raw.<em>somefilename</em>.</td>

+    </tr>

+</table>

+<p>Resources are compiled into the final APK file. Android creates a wrapper class,

+    called R, that you can use to refer to these resources in your code. R contains subclasses

+    named according to the path and file name of the source file</p>

+<a name="colorvals" id="colorvals"></a>

+<h3>Global Resource Notes</h3>

+<ul>

+    <li>Several resources allow you to define colors. Android accepts color values

+        written in various web-style formats -- a hexadecimal constant in any of the

+        following forms: #RGB, #ARGB, #RRGGBB, #AARRGGBB. </li>

+    <li>All color values support setting an alpha channel value, where the first

+        two hexadecimal numbers specify the transparency. Zero in the alpha channel

+        means transparent. The default value is opaque. </li>

+</ul>

+<a name="UsingResources" id="UsingResources"></a>

+<h2>Using Resources </h2>

+<p>This section describes how to use the resources you've created. It includes the

+    following topics:</p>

+<ul>

+    <li><a href="#ResourcesInCode">Using resources in code</a>&nbsp;- How to call

+        resources in your code to instantiate them. </li>

+    <li><a href="#ReferencesToResources">Referring to resources from other resources</a> &nbsp;-

+        You can reference resources from other resources. This lets you reuse common 

+        resource values inside resources. </li>

+    <li><a href="#AlternateResources">Supporting Alternate Resources for Alternate

+            Configurations</a> - You can specify different resources

+            to load, depending on the language or display configuration of the host

+            hardware. </li>

+</ul>

+<p>At compile time, Android generates a class named R that contains resource identifiers

+    to all the resources in your program. This class contains several subclasses,

+    one for each type of resource supported by Android, and for which you provided

+    a resource file. Each class contains one or more identifiers for the compiled resources,

+    that you use in your code to load the resource. Here is a small resource file

+    that contains string, layout (screens or parts of screens), and image resources.</p>

+<p class="note"><strong>Note:</strong> the R class is an auto-generated file and is not

+designed to be edited by hand. It will be automatically re-created as needed when

+the resources are updated.</p>

+<pre class="prettyprint">package com.android.samples;

+public final class R {

+    public static final class string {

+        public static final int greeting=0x0204000e;

+        public static final int start_button_text=0x02040001;

+        public static final int submit_button_text=0x02040008;

+        public static final int main_screen_title=0x0204000a;

+    };

+    public static final class layout {

+        public static final int start_screen=0x02070000;

+        public static final int new_user_pane=0x02070001;

+        public static final int select_user_list=0x02070002;

+

+    };

+    public static final class drawable {

+        public static final int company_logo=0x02020005;

+        public static final int smiling_cat=0x02020006;

+        public static final int yellow_fade_background=0x02020007;

+        public static final int stretch_button_1=0x02020008;

+

+    };

+};

+</pre>

+<a name="ResourcesInCode" id="ResourcesInCode"></a>

+<h3>Using Resources in Code </h3>

+

+<p>Using resources in code is just a matter of knowing the full resource ID

+and what type of object your resource has been compiled into. Here is the

+syntax for referring to a resource:</p>

+<p><code>R.<em>resource_type</em>.<em>resource_name</em></code></p>

+<p>or</p>

+<p><code>android.R.<em>resource_type</em>.<em>resource_name</em></code></p>

+

+<p>Where <code>resource_type</code> is the R subclass that holds a specific type

+of resource. <code>resource_name</code> is the <em>name</em> attribute for resources

+defined in XML files, or the file name (without the extension) for resources

+defined by other file types. Each type of resource will be added to a specific

+R subclass, depending on the type of resource it is; to learn which R subclass

+hosts your compiled resource type, consult the 

+<a href="available-resources.html">Available Resources</a> document. Resources compiled by your own application can

+be referred to without a package name (simply as

+<code>R.<em>resource_type</em>.<em>resource_name</em></code>). Android contains

+a number of standard resources, such as screen styles and button backgrounds. To

+refer to these in code, you must qualify them with <code>android</code>, as in

+<code>android.R.drawable.button_background</code>.</p>

+

+<p>Here are some good and bad examples of using compiled resources in code:</p>

+

+<pre class="prettyprint">// Load a background for the current screen from a drawable resource.

+this.getWindow().setBackgroundDrawableResource(R.drawable.my_background_image);

+

+// WRONG Sending a string resource reference into a 

+// method that expects a string.

+this.getWindow().setTitle(R.string.main_title);

+

+// RIGHT Need to get the title from the Resources wrapper.

+this.getWindow().setTitle(Resources.getText(R.string.main_title));

+

+// Load a custom layout for the current screen.

+setContentView(R.layout.main_screen);

+

+// Set a slide in animation for a ViewFlipper object.

+mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, 

+        R.anim.hyperspace_in));

+

+// Set the text on a TextView object.

+TextView msgTextView = (TextView)findViewByID(R.id.msg);

+msgTextView.setText(R.string.hello_message); </pre>

+

+<a name="ReferencesToResources" id="ReferencesToResources"></a>

+<h3>References to Resources</h3>

+

+<p>A value supplied in an attribute (or resource) can also be a reference to

+a resource.  This is often used in layout files to supply strings (so they

+can be localized) and images (which exist in another file), though a reference

+can be any resource type including colors and integers.</p>

+

+<p>For example, if we have 

+<a href="available-resources.html#colordrawableresources">color 

+resources</a>, we can write a layout file that sets the text color size to be

+the value contained in one of those resources:</p>

+

+<pre>

+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

+&lt;EditText id=&quot;text&quot;

+    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;

+    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;

+    <strong>android:textColor=&quot;&#64;color/opaque_red&quot;</strong>

+    android:text=&quot;Hello, World!&quot; /&gt;

+</pre>

+

+<p>Note here the use of the '@' prefix to introduce a resource reference -- the

+text following that is the name of a resource in the form

+of <code>@[package:]type/name</code>.  In this case we didn't need to specify

+the package because we are referencing a resource in our own package.  To

+reference a system resource, you would need to write:</p>

+

+<pre>

+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

+&lt;EditText id=&quot;text&quot;

+    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;

+    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;

+    android:textColor=&quot;&#64;<strong>android:</strong>color/opaque_red&quot;

+    android:text=&quot;Hello, World!&quot; /&gt;

+</pre>

+

+<p>As another example, you should always use resource references when supplying

+strings in a layout file so that they can be localized:</p>

+

+<pre>

+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

+&lt;EditText id=&quot;text&quot;

+    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;

+    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;

+    android:textColor=&quot;&#64;android:color/opaque_red&quot;

+    android:text=&quot;&#64;string/hello_world&quot; /&gt;

+</pre>

+

+<p>This facility can also be used to create references between resources.

+For example, we can create new drawable resources that are aliases for

+existing images:</p>

+

+<pre>

+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

+&lt;resources&gt;

+    &lt;drawable id=&quot;my_background&quot;&gt;&#64;android:drawable/theme2_background&lt;/drawable&gt;

+&lt;/resources&gt;

+</pre>

+

+<a name="ReferencesToThemeAttributes"></a>

+<h3>References to Theme Attributes</h3>

+

+<p>Another kind of resource value allows you to reference the value of an

+attribute in the current theme.  This attribute reference can <em>only</em>

+be used in style resources and XML attributes; it allows you to customize the

+look of UI elements by changing them to standard variations supplied by the

+current theme, instead of supplying more concrete values.</p>

+

+<p>As an example, we can use this in our layout to set the text color to

+one of the standard colors defined in the base system theme:</p>

+

+<pre>

+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

+&lt;EditText id=&quot;text&quot;

+    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;

+    android:layout_width=&quot;fill_parent&quot; android:layout_height=&quot;fill_parent&quot;

+    <strong>android:textColor=&quot;?android:textDisabledColor&quot;</strong>

+    android:text=&quot;&#64;string/hello_world&quot; /&gt;

+</pre>

+

+<p>Note that this is very similar to a resource reference, except we are using

+an '?' prefix instead of '@'.  When you use this markup, you are supplying

+the name of an attribute resource that will be looked up in the theme --

+because the resource tool knows that an attribute resource is expected,

+you do not need to explicitly state the type (which would be

+<code>?android:attr/android:textDisabledColor</code>).</p>

+

+<p>Other than using this resource identifier to find the value in the

+theme instead of raw resources, the name syntax is identical to the '@' format:

+<code>?[namespace:]type/name</code> with the type here being optional.</p>

+

+<a name="UsingSystemResources"></a>

+<h3>Using System Resources</h3>

+

+<p>Many resources included with the system are available to applications.

+All such resources are defined under the class "android.R".  For example,

+you can display the standard application icon in a screen with the following

+code:</p>

+

+<pre class="prettyprint">

+public class MyActivity extends Activity

+{

+    public void onStart() 

+    {

+        requestScreenFeatures(FEATURE_BADGE_IMAGE);

+

+        super.onStart();

+

+        setBadgeResource(android.R.drawable.sym_def_app_icon);

+    }

+}

+</pre>

+

+<p>In a similar way, this code will apply to your screen the standard

+"green background" visual treatment defined by the system:</p>

+

+<pre class="prettyprint">

+public class MyActivity extends Activity

+{

+    public void onStart() 

+    {

+        super.onStart();

+

+        setTheme(android.R.style.Theme_Black);

+    }

+}

+</pre>

+

+<a name="AlternateResources" id="AlternateResources"></a>

+<h2>Alternate Resources (for alternate languages and configurations)</h2>

+

+<p>You can supply different resources for your application to use depending on the UI

+language or hardware configuration on the device. Note that although you can

+include different string, layout, and other resources, the SDK does not expose

+methods to let you specify which alternate resource set to load. Android

+detects the proper set for the hardware and location, and loads them as

+appropriate. Users can select alternate language settings using the settings

+panel on the device. </p>

+<p>To include alternate resources, create parallel resource folders with

+qualifiers appended to the folder names, indicating the configuration it

+applies to (language, screen orientation, and so on). For example, here is a

+project that holds one string resource file for English, and another for

+French:</p>

+

+<pre>

+MyApp/

+    res/

+        values-en/

+            strings.xml

+        values-fr/

+            strings.xml

+</pre>

+

+<p>Android supports several types of qualifiers, with various values for each.

+Append these to the end of the resource folder name, separated by dashes. You

+can add multiple qualifiers to each folder name, but they must appear in the

+order they are listed here. For example, a folder containing drawable

+resources for a fully specified configuration would look like this:</p>

+

+<pre>

+MyApp/

+    res/

+        drawable-en-rUS-port-160dpi-finger-keysexposed-qwerty-dpad-480x320/

+</pre>

+

+<p>More typically, you will only specify a few specific configuration options. You may drop any of the values from the

+complete list, as long as the remaining values are still in the same

+order:</p>

+

+<pre>

+MyApp/

+    res/

+        drawable-en-rUS-finger/

+        drawable-port/

+        drawable-port-160dpi/

+        drawable-qwerty/

+</pre>

+<p>Table 2 lists the valid folder-name qualifiers, in order of precedence. Qualifiers that are listed higher in the table take precedence over those listed lower, as described in <a href="#best-match">How Android finds the best matching directory</a>. </p>

+<p class="caption" id="table2">Table 2</p>

+<table border="1">

+    <tr>

+        <th> Qualifier </th>

+        <th> Values </th>

+    </tr>

+    <tr>

+      <td>MCC and MNC</td>

+      <td>The <a href="http://en.wikipedia.org/wiki/Mobile_country_code">mobile country code</a> and <a href="http://en.wikipedia.org/wiki/Mobile_Network_Code">mobile network code</a> from the SIM in the device. For example  <code>mcc310-mnc004</code> (U.S., Verizon brand); <code>mcc208-mnc00</code> (France, Orange brand); <code>mcc234-mnc00</code> (U.K., BT brand). <br>

+        <br>

+        If the device uses a radio connection  (GSM phone), the MCC will come from the SIM, and the MNC will come from the  network to which the device is attached. You might sometimes use the MCC alone, for example to include country-specific legal resources in your application. If your application specifies resources for a MCC/MNC  combination, those resources can only be used if both the MCC and the MNC match. </td>

+  </tr>

+    <tr>

+        <td>Language and region</td>

+        <td>The two letter <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO

+                639-1</a> language code and two letter

+                <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO

+                3166-1-alpha-2</a> region code (preceded by lowercase &quot;r&quot;). For example 

+                <code>en-rUS</code>, <code>fr-rFR</code>, <code>es-rES</code>. <br>

+                <br>

+          The codes are case-sensitive: The language code is lowercase, and the country code is uppercase. You cannot specify a region alone, but you can specify a language alone, for example <code>en</code>, <code>fr</code>, <code>es</code>. </td>

+  </tr>

+    <tr>

+        <td>Screen orientation</td>

+        <td><code>port</code>, <code>land</code>, <code>square</code> </td>

+    </tr>

+    <tr>

+        <td>Screen pixel density</td>

+        <td><code>92dpi</code>, <code>108dpi</code>, etc. When Android selects which resource files to use, it handles screen density  differently than the other qualifiers. In step 1 of <a href="#best-match">How Android finds the best matching directory</a> (below),  screen density is always  considered to be a match. In step 4, if the qualifier being considered is screen density, Android will select the best final match at that point, without any need to move on to step 5. </td>

+  </tr>

+    <tr>

+        <td>Touchscreen type</td>

+        <td><code>notouch</code>, <code>stylus</code>, <code>finger</code></td>

+    </tr>

+    <tr>

+        <td>Whether the keyboard is available to the user</td>

+        <td><code>keysexposed</code>, <code>keyshidden</code>, <code>keyssoft</code> <br>

+          If your application has specific resources that should only be used with a soft keyboard, use the <code>keyssoft</code> value. If no <code>keyssoft</code> resources are available (only <code>keysexposed</code> and <code>keyshidden</code>) and the device  shows a soft keyboard,  the system will use <code>keysexposed</code> resources. </td>

+  </tr>

+    <tr>

+        <td>Primary text input method</td>

+        <td><code>nokeys</code>, <code>qwerty</code>, <code>12key</code> </td>

+    </tr>

+    <tr>

+        <td>Primary non-touchscreen<br />

+            navigation method</td>

+        <td><code>nonav</code>, <code>dpad</code>, <code>trackball</code>, <code>wheel</code> </td>

+    </tr>

+    <tr>

+        <td>Screen dimensions</td>

+        <td><code>320x240</code>, <code>640x480</code>, etc. The larger dimension

+            must be specified first. </td>

+    </tr>

+    <tr>

+      <td>SDK version</td>

+      <td>The SDK version supported by the device, for example <code>v3</code>. The Android 1.0 SDK is <code>v1, </code> the 1.1 SDK is <code>v2</code>, and the 1.5 SDK is <code>v3</code>.</td>

+  </tr>

+    <tr>

+      <td>(Minor version)</td>

+      <td>(You cannot currently    specify minor version. It is always set to 0.)</td>

+  </tr>

+</table>

+

+<p>This list does not include device-specific parameters such as carrier,

+branding, device/hardware, or manufacturer. Everything that an application

+needs to know about the device that it is running on is encoded via the

+resource qualifiers in the table above.</p>

+

+<p>All resource directories, qualified and unqualified, live under the <code>res/</code> folder. Here are some  guidelines on qualified resource directory names:</p>

+

+<ul>

+    <li>You can specify multiple qualifiers, separated by dashes. For example, <code>drawable-en-rUS-land</code> will apply to US-English

+    devices in landscape orientation. </li>

+    <li>The qualifiers must  be in the order listed in <a href="#table2">Table 2</a> above. For example:

+      <ul>

+        <li>Correct: <code>values-mcc460-nokeys/</code></li>

+        <li>Incorrect: <code>values-nokeys-mcc460/</code></li>

+      </ul>

+    </li>

+    <li>Values are case-sensitive. For example, a portrait-specific <code>drawable</code> directory must be named

+    <code>drawable-port</code>, not <code>drawable-PORT</code> or <code>drawable-Port</code>.</li>

+    <li>Only one value for each qualifier type is supported. For example, if you want to use exactly the same drawable files for Spain and France, you will need two  resource directories, such as <code>drawable-rES/</code> and <code>drawable-rFR/</code>, containing identical files. You cannot 

+        have a directory named <code>drawable-rES-rFR/</code>. </li>

+    <li>Qualified directories cannot be nested. For example, you cannot have <code>res/drawable/drawable-en</code>. </li>

+</ul>

+

+<h3>How resources are referenced in code</h3>

+<p>All resources will be referenced in code or resource reference syntax by

+    their simple, undecorated names. So if a resource were named this:<br />

+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>MyApp/res/drawable-port-92dpi/myimage.png</code><br />

+  It would be referenced as this:<br />

+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>R.drawable.myimage</code> (code)<br />

+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>&#064;drawable/myimage</code> (XML)</p>

+<p>If several drawable directories are available, Android will select one of them (as described below) and load  <code>myimage.png</code> from it.</p>

+<h3 id="best-match">How Android finds the best matching directory </h3>

+

+<p>Android will pick which of the various underlying resource files should be

+used at runtime, depending on the current configuration of the device. The example used here assumes the following device configuration:</p>

+<blockquote>

+  <p>Locale = <code>en-GB</code><br>

+  Screen orientation = <code>port</code><br>

+  Screen pixel density = <code>108dpi</code><br>

+    Touchscreen type = <code>notouch</code><br>

+    Primary text input method = <code>12key</code><br>

+  </p>

+</blockquote>

+<p>Here is how  Android  makes the selection: </p>

+<ol>

+    <li>

+            Eliminate  resource files that contradict the 

+            device configuration. For example, assume that the following resource directories are available for drawables. The <code>drawable-fr-rCA/</code> directory will be eliminated, because it contradicts the locale of the device.<br>

+<pre>MyApp/res/drawable/

+MyApp/res/drawable-en/

+<strike>MyApp/res/drawable-fr-rCA/</strike>

+MyApp/res/drawable-en-port/

+MyApp/res/drawable-en-notouch-12key/

+MyApp/res/drawable-port-92dpi/

+MyApp/res/drawable-port-notouch-12key</pre>

+      <strong>Exception: </strong>Screen pixel density is the one qualifier that is not used to eliminate files. Even though the screen density of the device is 108 dpi, <code>drawable-port-92dpi/</code> is not  eliminated from the list, because every screen density is considered to be a 

+        match at this point.</li>

+    <li>From <a href="#table2">Table 2</a>, pick the   highest-precedence qualifier that remains in the list. (Start with MCC, then move down through the list.) </li>

+  <li>Do any of the available resource directories include this qualifier?  </li>

+  <ul>

+    <li>If No, return to step 2 and look at the next qualifier listed in Table 2. In our example, the answer is &quot;no&quot; until we reach Language.</li>

+    <li>If Yes, move on to step 4.</li>

+  </ul>

+  <li>Eliminate resource directories that do not include this qualifier. In our example, we eliminate all the directories that do not include a language qualifier. </li>

+  <pre><strike>MyApp/res/drawable/</strike>

+MyApp/res/drawable-en/

+MyApp/res/drawable-en-port/

+MyApp/res/drawable-en-notouch-12key/

+<strike>MyApp/res/drawable-port-92dpi/</strike>

+<strike>MyApp/res/drawable-port-notouch-12key</strike></pre>

+  <strong>Exception:</strong> If the qualifier in question  is screen pixel density, Android will select the option that most closely matches the device, and the selection process will be complete. In general, Android will prefer scaling down a larger original image to scaling  up a smaller original image.<br><br></li>

+

+<li>Go back and repeat steps 2, 3, and 4 until only one choice remains. In the example, screen orientation is the next qualifier in the table for which we have any matches.

+    Eliminate resources that do not specify a screen orientation. </p>

+    <pre><strike>MyApp/res/drawable-en/</strike>

+MyApp/res/drawable-en-port/

+<strike>MyApp/res/drawable-en-notouch-12key/</strike></pre>

+  Only one choice remains, so that's it. When drawables are called for in this example application, the Android system will load resources from the <code>MyApp/res/drawable-en-port/</code> directory.

+</ol>

+<p class="note"><strong>Tip:</strong> The <em>precedence</em> of the qualifiers is more important than the number of qualifiers that exactly match the device. For example, in step 4 above, the last choice on the list includes three qualifiers that exactly match the device (orientation, touchscreen type, and input method), while <code>drawable-en</code> has only one parameter that matches (language). However, language has a higher precedence, so <code>drawable-port-notouch-12key</code> is out.</p>

+<p>This flowchart summarizes how Android selects resource directories to load.</p>

+<p><img src="res-selection-flowchart.png" alt="resource-selection" width="461" height="471" style="margin:15px"></p>

+<h3>Terminology</h3>

+<p>The resource system brings a number of different pieces together to

+form the final complete resource functionality.  To help understand the

+overall system, here are some brief definitions of the core concepts and

+components you will encounter in using it:</p>

+

+<p><strong>Asset</strong>: A single blob of data associated with an application. This

+includes object files compiled from the Java source code, graphics (such as PNG

+images), XML files, etc. These files are organized in a directory hierarchy

+that, during final packaging of the application, is bundled together into a

+single ZIP file.</p>

+

+<p><strong>aapt</strong>: Android Asset Packaging Tool. The tool that generates the 

+final ZIP file of application assets.  In addition to collecting raw assets 

+together, it also parses resource definitions into binary asset data.</p>

+

+<p><strong>Resource Table</strong>: A special asset that aapt generates for you,

+describing all of the resources contained in an application/package.

+This file is accessed for you by the Resources class; it is not touched

+directly by applications.</p>

+

+<p><strong>Resource</strong>: An entry in the Resource Table describing a single

+named value.  Broadly, there are two types of resources: primitives and

+bags.</p>

+

+<p><strong>Resource Identifier</strong>: In the Resource Table all resources are

+identified by a unique integer number.  In source code (resource descriptions,

+XML files, Java source code) you can use symbolic names that stand as constants for

+the actual resource identifier integer.</p>

+

+<p><strong>Primitive Resource</strong>: All primitive resources can be written as a

+simple string, using formatting to describe a variety of primitive types

+included in the resource system: integers, colors, strings, references to

+other resources, etc.  Complex resources, such as bitmaps and XML

+describes, are stored as a primitive string resource whose value is the path

+of the underlying Asset holding its actual data.</p>

+

+<p><strong>Bag Resource</strong>: A special kind of resource entry that, instead of a

+simple string, holds an arbitrary list of name/value pairs.  Each name is

+itself a resource identifier, and each value can hold

+the same kinds of string formatted data as a normal resource.  Bags also

+support inheritance: a bag can inherit the values from another bag, selectively

+replacing or extending them to generate its own contents.</p>

+

+<p><strong>Kind</strong>: The resource kind is a way to organize resource identifiers

+for various purposes.  For example, drawable resources are used to

+instantiate Drawable objects, so their data is a primitive resource containing

+either a color constant or string path to a bitmap or XML asset.  Other

+common resource kinds are string (localized string primitives), color

+(color primitives), layout (a string path to an XML asset describing a view

+layout), and style (a bag resource describing user interface attributes).

+There is also a standard "attr" resource kind, which defines the resource

+identifiers to be used for naming bag items and XML attributes</p>

+

+<p><strong>Style</strong>: The name of the resource kind containing bags that are used

+to supply a set of user interface attributes.  For example, a TextView class may

+be given a style resource that defines its text size, color, and alignment.

+In a layout XML file, you associate a style with a bag using the "style"

+attribute, whose value is the name of the style resource.</p>

+

+<p><strong>Style Class</strong>: Specifies a related set of attribute resources.

+This data is not placed in the resource table itself, but used to generate

+constants in the source code that make it easier for you to retrieve values out of

+a style resource and/or XML tag's attributes.  For example, the

+Android platform defines a "View" style class that

+contains all of the standard view attributes: padding, visibility,

+background, etc.; when View is inflated it uses this style class to

+retrieve those values from the XML file (at which point style and theme

+information is applied as approriate) and load them into its instance.</p>

+

+<p><strong>Configuration</strong>: For any particular resource identifier, there may be

+multiple different available values depending on the current configuration.

+The configuration includes the locale (language and country), screen

+orientation, etc.  The current configuration is used to

+select which resource values are in effect when the resource table is

+loaded.</p>

+

+<p><strong>Theme</strong>: A standard style resource that supplies global

+attribute values for a particular context.  For example, when writing an

+Activity the application developer can select a standard theme to use, such

+as the Theme.White or Theme.Black styles; this style supplies information

+such as the screen background image/color, default text color, button style,

+text editor style, text size, etc.  When inflating a layout resource, most

+values for widgets (the text color, selector, background) if not explicitly

+set will come from the current theme; style and attribute

+values supplied in the layout can also assign their value from explicitly

+named values in the theme attributes if desired.</p>

+

+<p><strong>Overlay</strong>: A resource table that does not define a new set of resources,

+but instead replaces the values of resources that are in another resource table.

+Like a configuration, this is applied at load time

+to the resource data; it can add new configuration values (for example

+strings in a new locale), replace existing values (for example change

+the standard white background image to a "Hello Kitty" background image),

+and modify resource bags (for example change the font size of the Theme.White

+style to have an 18 pt font size).  This is the facility that allows the

+user to select between different global appearances of their device, or

+download files with new appearances.</p>

+

+<h2>Resource Reference</h2>

+<p>The <a href="available-resources.html">Available Resources</a>

+document provides a detailed list of the various types of resource and how to use them

+from within the Java source code, or from other references.</p>

+

+<a name="i18n" id="i18n"></a>

+<h2>Internationalization and Localization</h2>

+<p class="note"><strong>Coming Soon:</strong> Internationalization and Localization are

+critical, but are also not quite ready yet in the current SDK. As the

+SDK matures, this section will contain information on the Internationalization

+and Localization features of the Android platform. In the meantime, it is a good

+idea to start by externalizing all strings, and practicing good structure in

+creating and using resources.</p>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
new file mode 100644
index 0000000..08d295d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.ColorFilter;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.util.Log;
+import android.os.SystemClock;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+import com.android.internal.R;
+
+/**
+ * @hide
+ */
+public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable {
+    private AnimatedRotateState mState;
+    private boolean mMutated;
+    private float mCurrentDegrees;
+    private float mIncrement;
+
+    public AnimatedRotateDrawable() {
+        this(null);
+    }
+
+    private AnimatedRotateDrawable(AnimatedRotateState rotateState) {
+        mState = new AnimatedRotateState(rotateState, this);
+        init();
+    }
+
+    private void init() {
+        final AnimatedRotateState state = mState;
+        mIncrement = 360.0f / (float) state.mFramesCount;
+        final Drawable drawable = state.mDrawable;
+        if (drawable != null) {
+            drawable.setFilterBitmap(true);
+            if (drawable instanceof BitmapDrawable) {
+                ((BitmapDrawable) drawable).setAntiAlias(true);
+            }
+        }
+    }
+
+    public void draw(Canvas canvas) {
+        int saveCount = canvas.save();
+
+        final AnimatedRotateState st = mState;
+        final Drawable drawable = st.mDrawable;
+        final Rect bounds = drawable.getBounds();
+
+        int w = bounds.right - bounds.left;
+        int h = bounds.bottom - bounds.top;
+
+        float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+        float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+
+        canvas.rotate(mCurrentDegrees, px, py);
+
+        drawable.draw(canvas);
+
+        canvas.restoreToCount(saveCount);
+        
+        nextFrame();
+    }
+    
+    private void nextFrame() {
+        unscheduleSelf(this);
+        scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
+    }
+    
+    public void run() {
+        // TODO: This should be computed in draw(Canvas), based on the amount
+        // of time since the last frame drawn 
+        mCurrentDegrees += mIncrement;
+        if (mCurrentDegrees > (360.0f - mIncrement)) {
+            mCurrentDegrees = 0.0f;
+        }
+        nextFrame();
+        invalidateSelf();
+    }
+    
+    @Override
+    public boolean setVisible(boolean visible, boolean restart) {
+        mState.mDrawable.setVisible(visible, restart);
+        boolean changed = super.setVisible(visible, restart);
+        if (visible) {
+            if (changed || restart) {
+                mCurrentDegrees = 0.0f;
+                nextFrame();
+            }
+        } else {
+            unscheduleSelf(this);
+        }
+        return changed;
+    }    
+    
+    /**
+     * Returns the drawable rotated by this RotateDrawable.
+     */
+    public Drawable getDrawable() {
+        return mState.mDrawable;
+    }
+
+    @Override
+    public int getChangingConfigurations() {
+        return super.getChangingConfigurations()
+                | mState.mChangingConfigurations
+                | mState.mDrawable.getChangingConfigurations();
+    }
+    
+    public void setAlpha(int alpha) {
+        mState.mDrawable.setAlpha(alpha);
+    }
+
+    public void setColorFilter(ColorFilter cf) {
+        mState.mDrawable.setColorFilter(cf);
+    }
+
+    public int getOpacity() {
+        return mState.mDrawable.getOpacity();
+    }
+
+    public void invalidateDrawable(Drawable who) {
+        if (mCallback != null) {
+            mCallback.invalidateDrawable(this);
+        }
+    }
+
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        if (mCallback != null) {
+            mCallback.scheduleDrawable(this, what, when);
+        }
+    }
+
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+        if (mCallback != null) {
+            mCallback.unscheduleDrawable(this, what);
+        }
+    }
+
+    @Override
+    public boolean getPadding(Rect padding) {
+        return mState.mDrawable.getPadding(padding);
+    }
+    
+    @Override
+    public boolean isStateful() {
+        return mState.mDrawable.isStateful();
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        mState.mDrawable.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mState.mDrawable.getIntrinsicWidth();
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mState.mDrawable.getIntrinsicHeight();
+    }
+
+    @Override
+    public ConstantState getConstantState() {
+        if (mState.canConstantState()) {
+            mState.mChangingConfigurations = super.getChangingConfigurations();
+            return mState;
+        }
+        return null;
+    }
+
+    @Override
+    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+            throws XmlPullParserException, IOException {
+
+        final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable);
+
+        super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
+        
+        TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
+        final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
+        final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        
+        tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
+        final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
+        final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        
+        final int framesCount = a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12);
+        final int frameDuration = a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150);
+        
+        final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
+        Drawable drawable = null;
+        if (res > 0) {
+            drawable = r.getDrawable(res);
+        }
+
+        a.recycle();
+        
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
+               (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if ((drawable = Drawable.createFromXmlInner(r, parser, attrs)) == null) {
+                Log.w("drawable", "Bad element under <animated-rotate>: "
+                        + parser .getName());
+            }
+        }
+
+        if (drawable == null) {
+            Log.w("drawable", "No drawable specified for <animated-rotate>");
+        }
+
+        final AnimatedRotateState rotateState = mState;
+        rotateState.mDrawable = drawable;
+        rotateState.mPivotXRel = pivotXRel;
+        rotateState.mPivotX = pivotX;
+        rotateState.mPivotYRel = pivotYRel;
+        rotateState.mPivotY = pivotY;
+        rotateState.mFramesCount = framesCount;
+        rotateState.mFrameDuration = frameDuration;
+
+        init();
+
+        if (drawable != null) {
+            drawable.setCallback(this);
+        }
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mState.mDrawable.mutate();
+            mMutated = true;
+        }
+        return this;
+    }
+
+    final static class AnimatedRotateState extends Drawable.ConstantState {
+        Drawable mDrawable;
+
+        int mChangingConfigurations;
+        
+        boolean mPivotXRel;
+        float mPivotX;
+        boolean mPivotYRel;
+        float mPivotY;
+        int mFrameDuration;
+        int mFramesCount;
+
+        private boolean mCanConstantState;
+        private boolean mCheckedConstantState;        
+
+        public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner) {
+            if (source != null) {
+                mDrawable = source.mDrawable.getConstantState().newDrawable();
+                mDrawable.setCallback(owner);
+                mPivotXRel = source.mPivotXRel;
+                mPivotX = source.mPivotX;
+                mPivotYRel = source.mPivotYRel;
+                mPivotY = source.mPivotY;
+                mFramesCount = source.mFramesCount;
+                mFrameDuration = source.mFrameDuration;
+                mCanConstantState = mCheckedConstantState = true;
+            }
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimatedRotateDrawable(this);
+        }
+        
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConfigurations;
+        }
+
+        public boolean canConstantState() {
+            if (!mCheckedConstantState) {
+                mCanConstantState = mDrawable.getConstantState() != null;
+                mCheckedConstantState = true;
+            }
+
+            return mCanConstantState;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index f0d49f5..910e111 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -745,6 +745,8 @@
             drawable = new ClipDrawable();
         } else if (name.equals("rotate")) {
             drawable = new RotateDrawable();
+        } else if (name.equals("animated-rotate")) {
+            drawable = new AnimatedRotateDrawable();            
         } else if (name.equals("animation-list")) {
             drawable = new AnimationDrawable();
         } else if (name.equals("inset")) {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 3db45f0..a7a8708 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -880,7 +880,9 @@
             mShape = state.mShape;
             mGradient = state.mGradient;
             mOrientation = state.mOrientation;
-            mColors = state.mColors.clone();
+            if (state.mColors != null) {
+                mColors = state.mColors.clone();
+            }
             if (state.mPositions != null) {
                 mPositions = state.mPositions.clone();
             }
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 6b0cc8a..eafa661 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -71,6 +71,82 @@
         TONE_SUP_CONGESTION_ABBREV, // Abbreviated congestion: congestion tone limited to 4 seconds
         TONE_SUP_CONFIRM, // Confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle.
         TONE_SUP_PIP, // Pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
+
+        // CDMA Tones
+        TONE_CDMA_DIAL_TONE_LITE,
+        TONE_CDMA_NETWORK_USA_RINGBACK,
+        TONE_CDMA_INTERCEPT,
+        TONE_CDMA_ABBR_INTERCEPT,
+        TONE_CDMA_REORDER,
+        TONE_CDMA_ABBR_REORDER,
+        TONE_CDMA_NETWORK_BUSY,
+        TONE_CDMA_CONFIRM,
+        TONE_CDMA_ANSWER,
+        TONE_CDMA_NETWORK_CALLWAITING,
+        TONE_CDMA_PIP,
+
+        // ISDN
+        TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL,  // ISDN Alert Normal
+        TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP, // ISDN Intergroup
+        TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI, // ISDN SP PRI
+        TONE_CDMA_CALL_SIGNAL_ISDN_PAT3,  // ISDN Alert PAT3
+        TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING, // ISDN Alert PING RING
+        TONE_CDMA_CALL_SIGNAL_ISDN_PAT5,  // ISDN Alert PAT5
+        TONE_CDMA_CALL_SIGNAL_ISDN_PAT6,  // ISDN Alert PAT6
+        TONE_CDMA_CALL_SIGNAL_ISDN_PAT7,  // ISDN Alert PAT7
+        // ISDN end
+
+        // IS54
+        TONE_CDMA_HIGH_L,  // IS54 High Pitch Long
+        TONE_CDMA_MED_L, // IS54 Med Pitch Long
+        TONE_CDMA_LOW_L, // IS54 Low Pitch Long
+        TONE_CDMA_HIGH_SS, // IS54 High Pitch Short Short
+        TONE_CDMA_MED_SS, // IS54 Medium Pitch Short Short
+        TONE_CDMA_LOW_SS, // IS54 Low Pitch Short Short
+        TONE_CDMA_HIGH_SSL, // IS54 High Pitch Short Short Long
+        TONE_CDMA_MED_SSL, // IS54 Medium  Pitch Short Short Long
+        TONE_CDMA_LOW_SSL, // IS54 Low  Pitch Short Short Long
+        TONE_CDMA_HIGH_SS_2, // IS54 High Pitch Short Short 2
+        TONE_CDMA_MED_SS_2, // IS54 Med Pitch Short Short 2
+        TONE_CDMA_LOW_SS_2, // IS54 Low  Pitch Short Short 2
+        TONE_CDMA_HIGH_SLS, // IS54 High Pitch Short Long Short
+        TONE_CDMA_MED_SLS, // IS54 Med Pitch Short Long Short
+        TONE_CDMA_LOW_SLS, // IS54 Low Pitch Short Long Short
+        TONE_CDMA_HIGH_S_X4, // IS54 High Pitch Short Short Short Short
+        TONE_CDMA_MED_S_X4, // IS54 Med Pitch Short Short Short Short
+        TONE_CDMA_LOW_S_X4, // IS54 Low Pitch Short Short Short Short
+        TONE_CDMA_HIGH_PBX_L, // PBX High Pitch Long
+        TONE_CDMA_MED_PBX_L, // PBX Med Pitch Long
+        TONE_CDMA_LOW_PBX_L, // PBX Low  Pitch Long
+        TONE_CDMA_HIGH_PBX_SS, // PBX High Short Short
+        TONE_CDMA_MED_PBX_SS, // PBX Med Short Short
+        TONE_CDMA_LOW_PBX_SS, // PBX Low  Short Short
+        TONE_CDMA_HIGH_PBX_SSL, // PBX High Short Short Long
+        TONE_CDMA_MED_PBX_SSL, // PBX Med Short Short Long
+        TONE_CDMA_LOW_PBX_SSL,  // PBX Low Short Short Long
+        TONE_CDMA_HIGH_PBX_SLS, // PBX High  SLS
+        TONE_CDMA_MED_PBX_SLS,  // PBX Med SLS
+        TONE_CDMA_LOW_PBX_SLS, // PBX Low SLS
+        TONE_CDMA_HIGH_PBX_S_X4, // PBX High SSSS
+        TONE_CDMA_MED_PBX_S_X4, // PBX Med SSSS
+        TONE_CDMA_LOW_PBX_S_X4, // PBX LOW SSSS
+        //IS54 end
+        // proprietary
+        TONE_CDMA_ALERT_NETWORK_LITE,
+        TONE_CDMA_ALERT_AUTOREDIAL_LITE,
+        TONE_CDMA_ONE_MIN_BEEP,
+        TONE_CDMA_KEYPAD_VOLUME_KEY_LITE,
+        TONE_CDMA_PRESSHOLDKEY_LITE,
+        TONE_CDMA_ALERT_INCALL_LITE,
+        TONE_CDMA_EMERGENCY_RINGBACK,
+        TONE_CDMA_ALERT_CALL_GUARD,
+        TONE_CDMA_SOFT_ERROR_LITE,
+        TONE_CDMA_CALLDROP_LITE,
+        // proprietary end
+        TONE_CDMA_NETWORK_BUSY_ONE_SHOT,
+        TONE_CDMA_ABBR_ALERT,
+        TONE_CDMA_SIGNAL_OFF,
+        //CDMA end
         NUM_TONES,
         NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
     };
@@ -125,7 +201,7 @@
     static const unsigned char sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES];
 
     static const unsigned int TONEGEN_MAX_WAVES = 3;     // Maximun number of sine waves in a tone segment
-    static const unsigned int TONEGEN_MAX_SEGMENTS = 5;  // Maximun number of segments in a tone descriptor
+    static const unsigned int TONEGEN_MAX_SEGMENTS = 12;  // Maximun number of segments in a tone descriptor
     static const unsigned int TONEGEN_INF = 0xFFFFFFFF;  // Represents infinite time duration
     static const float TONEGEN_GAIN = 0.9;  // Default gain passed to  WaveGenerator().
 
@@ -140,6 +216,8 @@
     //        correspond to tone ON state and segments with odd index to OFF state.
     //        The data stored in segments[] is the duration of the corresponding period in ms.
     //        The first segment encountered with a 0 duration    indicates that no more segment follows.
+    //    - loopCnt - Number of times to repeat a sequence of seqments after playing this
+    //    - loopIndx - The segment index to go back and play is loopcnt > 0
     //    - repeatCnt indicates the number of times the sequence described by segments[] array must be repeated.
     //        When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
     //        If mCurCount > repeatCnt, the tone is stopped automatically. Otherwise, tone sequence will be
@@ -150,6 +228,8 @@
     public:
         unsigned int duration;
         unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
+        unsigned short loopCnt;
+        unsigned short loopIndx;
     };
 
     class ToneDescriptor {
@@ -174,6 +254,8 @@
     const ToneDescriptor *mpToneDesc;  // pointer to active tone descriptor
     const ToneDescriptor *mpNewToneDesc;  // pointer to next active tone descriptor
 
+    unsigned short mLoopCounter; // Current tone loopback count
+
     int mSamplingRate;  // AudioFlinger Sampling rate
     AudioTrack *mpAudioTrack;  // Pointer to audio track used for playback
     Mutex mLock;  // Mutex to control concurent access to ToneGenerator object from audio callback and application API
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 8486532..21cb73b 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -69,6 +69,14 @@
     TTS_MISSING_RESOURCES       = -6
 };
 
+enum tts_support_result {
+    TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
+    TTS_LANG_COUNTRY_AVAILABLE = 1,
+    TTS_LANG_AVAILABLE = 0,
+    TTS_LANG_MISSING_DATA = -1,
+    TTS_LANG_NOT_SUPPORTED = -2
+};
+
 class TtsEngine
 {
 public:
@@ -86,19 +94,32 @@
     // @return TTS_SUCCESS, or TTS_FAILURE
     virtual tts_result stop();
 
+    // Returns the level of support for the language, country and variant.
+    // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
+    //            and the corresponding resources are correctly installed
+    //         TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
+    //             corresponding resources are correctly installed, but there is no match for
+    //             the specified variant
+    //         TTS_LANG_AVAILABLE if the language is supported and the
+    //             corresponding resources are correctly installed, but there is no match for
+    //             the specified country and variant
+    //         TTS_LANG_MISSING_DATA if the required resources to provide any level of support
+    //             for the language are not correctly installed
+    //         TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
+    virtual tts_support_result isLanguageAvailable(const char *lang, const char *country,
+            const char *variant);
+
     // Load the resources associated with the specified language. The loaded
     // language will only be used once a call to setLanguage() with the same
-    // language value is issued. Language values are based on the Android
-    // conventions for localization as described in the Android platform
-    // documentation on internationalization. This implies that language
-    // data is specified in the format xx-rYY, where xx is a two letter
-    // ISO 639-1 language code in lowercase and rYY is a two letter
-    // ISO 3166-1-alpha-2 language code in uppercase preceded by a
-    // lowercase "r".
-    // @param value pointer to the language value
-    // @param size  length of the language value
+    // language value is issued. Language and country values are coded according to the ISO three
+    // letter codes for languages and countries, as can be retrieved from a java.util.Locale
+    // instance. The variant value is encoded as the variant string retrieved from a
+    // java.util.Locale instance built with that variant data.
+    // @param lang pointer to the ISO three letter code for the language
+    // @param country pointer to the ISO three letter code for the country
+    // @param variant pointer to the variant code
     // @return TTS_SUCCESS, or TTS_FAILURE
-    virtual tts_result loadLanguage(const char *value, const size_t size);
+    virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant);
     
     // Load the resources associated with the specified language, country and Locale variant.
     // The loaded language will only be used once a call to setLanguageFromLocale() with the same
@@ -112,16 +133,26 @@
     // @return TTS_SUCCESS, or TTS_FAILURE
     virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
 
-    // Retrieve the currently set language, or an empty "value" if no language
-    // has been set.
-    // @param[out]   value pointer to the retrieved language value
-    // @param[inout] iosize in: stores the size available to store the language
-    //                         value in *value
-    //                      out: stores the size required to hold the language
-    //                         value if  getLanguage() returned
-    //                         TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise.
-    // @return TTS_SUCCESS, or TTS_PROPERTY_SIZE_TOO_SMALL, or TTS_FAILURE
-    virtual tts_result getLanguage(char *value, size_t *iosize);
+    // Retrieve the currently set language, country and variant, or empty strings if none of
+    // parameters have been set. Language and country are represented by their 3-letter ISO code
+    // @param[out]   pointer to the retrieved 3-letter code language value
+    // @param[out]   pointer to the retrieved 3-letter code country value
+    // @param[out]   pointer to the retrieved variant value
+    // @return TTS_SUCCESS, or TTS_FAILURE
+    virtual tts_result getLanguage(char *language, char *country, char *variant);
+
+    // Notifies the engine what audio parameters should be used for the synthesis.
+    // This is meant to be used as a hint, the engine implementation will set the output values
+    // to those of the synthesis format, based on a given hint.
+    // @param[inout] encoding in: the desired audio sample format
+    //                         out: the format used by the TTS engine
+    // @param[inout] rate in: the desired audio sample rate
+    //                         out: the sample rate used by the TTS engine
+    // @param[inout] channels in: the desired number of audio channels
+    //                         out: the number of channels used by the TTS engine
+    // @return TTS_SUCCESS, or TTS_FAILURE
+    virtual tts_result setAudioFormat(AudioSystem::audio_format& encoding, uint32_t& rate,
+            int& channels);
 
     // Set a property for the the TTS engine
     // "size" is the maximum size of "value" for properties "property"
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 048bdd5..97e0e90 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -63,16 +63,12 @@
 #define FRAME_CALLBACK_FLAG_CAMERA                   0x05
 #define FRAME_CALLBACK_FLAG_BARCODE_SCANNER          0x07
 
-// msgType in notifyCallback function
+// msgType in notifyCallback and dataCallback functions
 enum {
-    CAMERA_MSG_ERROR,
+    CAMERA_MSG_ERROR = 0,
     CAMERA_MSG_SHUTTER,
     CAMERA_MSG_FOCUS,
-    CAMERA_MSG_ZOOM
-};
-
-// msgType in dataCallback function
-enum {
+    CAMERA_MSG_ZOOM,
     CAMERA_MSG_PREVIEW_FRAME,
     CAMERA_MSG_VIDEO_FRAME,
     CAMERA_MSG_POSTVIEW_FRAME,
@@ -86,10 +82,13 @@
 class Mutex;
 class String8;
 
-typedef void (*shutter_callback)(void *cookie);
-typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
-typedef void (*autofocus_callback)(bool focused, void *cookie);
-typedef void (*error_callback)(status_t err, void *cookie);
+// ref-counted object for callbacks
+class CameraListener: virtual public RefBase
+{
+public:
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+    virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+};
 
 class Camera : public BnCameraClient, public IBinder::DeathRecipient
 {
@@ -144,13 +143,8 @@
             // get preview/capture parameters - key/value pairs
             String8     getParameters() const;
 
-            void        setShutterCallback(shutter_callback cb, void *cookie);
-            void        setRawCallback(frame_callback cb, void *cookie);
-            void        setJpegCallback(frame_callback cb, void *cookie);
-            void        setRecordingCallback(frame_callback cb, void *cookie);
-            void        setPreviewCallback(frame_callback cb, void *cookie, int preview_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
-            void        setErrorCallback(error_callback cb, void *cookie);
-            void        setAutoFocusCallback(autofocus_callback cb, void *cookie);
+            void        setListener(const sp<CameraListener>& listener);
+            void        setPreviewCallbackFlags(int preview_callback_flag);
 
     // ICameraClient interface
     virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
@@ -160,6 +154,8 @@
 
 private:
                         Camera();
+                        Camera(const Camera&);
+                        Camera& operator=(const Camera);
                         virtual void binderDied(const wp<IBinder>& who);
 
             class DeathNotifier: public IBinder::DeathRecipient
@@ -179,20 +175,7 @@
             sp<ICamera>         mCamera;
             status_t            mStatus;
 
-            shutter_callback    mShutterCallback;
-            void                *mShutterCallbackCookie;
-            frame_callback      mRawCallback;
-            void                *mRawCallbackCookie;
-            frame_callback      mJpegCallback;
-            void                *mJpegCallbackCookie;
-            frame_callback      mPreviewCallback;
-            void                *mPreviewCallbackCookie;
-            frame_callback      mRecordingCallback;
-            void                *mRecordingCallbackCookie;
-            error_callback      mErrorCallback;
-            void                *mErrorCallbackCookie;
-            autofocus_callback  mAutoFocusCallback;
-            void                *mAutoFocusCallbackCookie;
+            sp<CameraListener>  mListener;
 
             friend class DeathNotifier;
 
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index a21359f..b1f5045 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -43,6 +43,7 @@
 struct FileState {
     int modTime_sec;
     int modTime_nsec;
+    int mode;
     int size;
     int crc32;
     int nameLen;
@@ -136,6 +137,7 @@
 
 private:
     void* m_buf;
+    bool m_loggedUnknownMetadata;
     KeyedVector<String8,FileRec> m_files;
 };
 
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index f1029b7..5c41ead 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -866,7 +866,7 @@
             uint8_t keyboard;
             uint8_t navigation;
             uint8_t inputFlags;
-            uint8_t pad0;
+            uint8_t inputPad0;
         };
         uint32_t input;
     };
@@ -905,6 +905,23 @@
         uint32_t version;
     };
     
+    enum {
+        SCREENLAYOUT_ANY  = 0x0000,
+        SCREENLAYOUT_SMALL = 0x0001,
+        SCREENLAYOUT_NORMAL = 0x0002,
+        SCREENLAYOUT_LARGE = 0x0003,
+    };
+    
+    union {
+        struct {
+            uint8_t screenLayout;
+            uint8_t screenConfigPad0;
+            uint8_t screenConfigPad1;
+            uint8_t screenConfigPad2;
+        };
+        uint32_t screenConfig;
+    };
+    
     inline void copyFromDeviceNoSwap(const ResTable_config& o) {
         const size_t size = dtohl(o.size);
         if (size >= sizeof(ResTable_config)) {
@@ -950,6 +967,8 @@
         diff = (int32_t)(screenSize - o.screenSize);
         if (diff != 0) return diff;
         diff = (int32_t)(version - o.version);
+        if (diff != 0) return diff;
+        diff = (int32_t)(screenLayout - o.screenLayout);
         return (int)diff;
     }
     
@@ -967,7 +986,8 @@
         CONFIG_ORIENTATION = 0x0080,
         CONFIG_DENSITY = 0x0100,
         CONFIG_SCREEN_SIZE = 0x0200,
-        CONFIG_VERSION = 0x0400
+        CONFIG_VERSION = 0x0400,
+        CONFIG_SCREEN_LAYOUT = 0x0800
     };
     
     // Compare two configuration, returning CONFIG_* flags set for each value
@@ -985,6 +1005,7 @@
         if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
         if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
         if (version != o.version) diffs |= CONFIG_VERSION;
+        if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
         return diffs;
     }
     
@@ -1062,6 +1083,13 @@
             }
         }
 
+        if (screenConfig || o.screenConfig) {
+            if (screenLayout != o.screenLayout) {
+                if (!screenLayout) return false;
+                if (!o.screenLayout) return true;
+            }
+        }
+
         if (version || o.version) {
             if (sdkVersion != o.sdkVersion) {
                 if (!sdkVersion) return false;
@@ -1191,6 +1219,12 @@
                 }
             }
 
+            if (screenConfig || o.screenConfig) {
+                if ((screenLayout != o.screenLayout) && requested->screenLayout) {
+                    return (screenLayout);
+                }
+            }
+
             if (version || o.version) {
                 if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
                     return (sdkVersion);
@@ -1282,6 +1316,12 @@
                 return false;
             }
         }
+        if (screenConfig != 0) {
+            if (settings.screenLayout != 0 && screenLayout != 0
+                && screenLayout != settings.screenLayout) {
+                return false;
+            }
+        }
         if (version != 0) {
             if (settings.sdkVersion != 0 && sdkVersion != 0
                 && sdkVersion != settings.sdkVersion) {
@@ -1310,13 +1350,13 @@
 
     String8 toString() const {
         char buf[200];
-        sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=0x%02x touch=0x%02x dens=0x%02x "
-                "kbd=0x%02x nav=0x%02x input=0x%02x screenW=0x%04x screenH=0x%04x vers=%d.%d",
+        sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d "
+                "kbd=%d nav=%d input=%d scrnW=%d scrnH=%d layout=%d vers=%d.%d",
                 mcc, mnc,
                 language[0] ? language[0] : '-', language[1] ? language[1] : '-',
                 country[0] ? country[0] : '-', country[1] ? country[1] : '-',
                 orientation, touchscreen, density, keyboard, navigation, inputFlags,
-                screenWidth, screenHeight, sdkVersion, minorVersion);
+                screenWidth, screenHeight, screenLayout, sdkVersion, minorVersion);
         return String8(buf);
     }
 };
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 0e998bf..ef4a8ea 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -771,10 +771,11 @@
             dirty.orSelf(layer->visibleRegionScreen);
             layer->contentDirty = false;
         } else {
-            // compute the exposed region
-            // dirty = what's visible now - what's wasn't covered before
-            //       = what's visible now & what's was covered before
-            dirty = visibleRegion.intersect(layer->coveredRegionScreen);            
+            /* compute the exposed region:
+             *    exposed = what's VISIBLE and NOT COVERED now 
+             *    but was COVERED before
+             */
+            dirty = (visibleRegion - coveredRegion) & layer->coveredRegionScreen;
         }
         dirty.subtractSelf(aboveOpaqueLayers);
 
@@ -783,7 +784,7 @@
 
         // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
         aboveOpaqueLayers.orSelf(opaqueRegion);
-        aboveCoveredLayers.orSelf(bounds);
+        aboveCoveredLayers.orSelf(visibleRegion);
         
         // Store the visible region is screen space
         layer->setVisibleRegion(visibleRegion);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index b3b2104b..7bbe38b 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -24,8 +24,7 @@
 	Region.cpp \
 	Surface.cpp \
 	SurfaceComposerClient.cpp \
-	SurfaceFlingerSynchro.cpp \
-	Time.cpp
+	SurfaceFlingerSynchro.cpp 
 
 LOCAL_SHARED_LIBRARIES := \
 	libcorecg \
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 6613700..bb22dab 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -85,20 +85,6 @@
 void Camera::init()
 {
     mStatus = UNKNOWN_ERROR;
-    mShutterCallback = 0;
-    mShutterCallbackCookie = 0;
-    mRawCallback = 0;
-    mRawCallbackCookie = 0;
-    mJpegCallback = 0;
-    mJpegCallbackCookie = 0;
-    mPreviewCallback = 0;
-    mPreviewCallbackCookie = 0;
-    mRecordingCallback = 0;
-    mRecordingCallbackCookie = 0;
-    mErrorCallback = 0;
-    mErrorCallbackCookie = 0;
-    mAutoFocusCallback = 0;
-    mAutoFocusCallbackCookie = 0;
 }
 
 Camera::~Camera()
@@ -127,7 +113,6 @@
 {
     LOGV("disconnect");
     if (mCamera != 0) {
-        mErrorCallback = 0;
         mCamera->disconnect();
         mCamera = 0;
     }
@@ -285,125 +270,49 @@
     return params;
 }
 
-void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
+void Camera::setListener(const sp<CameraListener>& listener)
 {
-    LOGV("setAutoFocusCallback");
-    mAutoFocusCallback = cb;
-    mAutoFocusCallbackCookie = cookie;
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
 }
 
-void Camera::setShutterCallback(shutter_callback cb, void *cookie)
+void Camera::setPreviewCallbackFlags(int flag)
 {
-    LOGV("setShutterCallback");
-    mShutterCallback = cb;
-    mShutterCallbackCookie = cookie;
-}
-
-void Camera::setRawCallback(frame_callback cb, void *cookie)
-{
-    LOGV("setRawCallback");
-    mRawCallback = cb;
-    mRawCallbackCookie = cookie;
-}
-
-void Camera::setJpegCallback(frame_callback cb, void *cookie)
-{
-    LOGV("setJpegCallback");
-    mJpegCallback = cb;
-    mJpegCallbackCookie = cookie;
-}
-
-void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
-{
-    LOGV("setPreviewCallback");
-    mPreviewCallback = cb;
-    mPreviewCallbackCookie = cookie;
+    LOGV("setPreviewCallbackFlags");
     sp <ICamera> c = mCamera;
     if (c == 0) return;
     mCamera->setPreviewCallbackFlag(flag);
 }
 
-void Camera::setRecordingCallback(frame_callback cb, void *cookie)
-{
-    LOGV("setRecordingCallback");
-    mRecordingCallback = cb;
-    mRecordingCallbackCookie = cookie;
-}
-
-void Camera::setErrorCallback(error_callback cb, void *cookie)
-{
-    LOGV("setErrorCallback");
-    mErrorCallback = cb;
-    mErrorCallbackCookie = cookie;
-}
-
 // callback from camera service
 void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
 {
-    switch(msgType) {
-    case CAMERA_MSG_ERROR:
-        LOGV("errorCallback");
-        if (mErrorCallback) {
-            mErrorCallback((status_t)ext1, mErrorCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_FOCUS:
-        LOGV("autoFocusCallback");
-        if (mAutoFocusCallback) {
-            mAutoFocusCallback((bool)ext1, mAutoFocusCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_SHUTTER:
-        LOGV("shutterCallback");
-        if (mShutterCallback) {
-            mShutterCallback(mShutterCallbackCookie);
-        }
-        break;
-    default:
-        LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
-        break;
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->notify(msgType, ext1, ext2);
     }
 }
 
 // callback from camera service when frame or image is ready
 void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
 {
-    switch(msgType) {
-    case CAMERA_MSG_PREVIEW_FRAME:
-        LOGV("previewCallback");
-        if (mPreviewCallback) {
-            mPreviewCallback(dataPtr, mPreviewCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_VIDEO_FRAME:
-        LOGV("recordingCallback");
-        if (mRecordingCallback) {
-            mRecordingCallback(dataPtr, mRecordingCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_RAW_IMAGE:
-        LOGV("rawCallback");
-        if (mRawCallback) {
-            mRawCallback(dataPtr, mRawCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_COMPRESSED_IMAGE:
-        LOGV("jpegCallback");
-        if (mJpegCallback) {
-            mJpegCallback(dataPtr, mJpegCallbackCookie);
-        }
-        break;
-    default:
-        LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
-        break;
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postData(msgType, dataPtr);
     }
 }
 
 void Camera::binderDied(const wp<IBinder>& who) {
     LOGW("ICamera died");
-    if (mErrorCallback) {
-        mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
-    }
+    notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0);
 }
 
 void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 0868cff..cce754a 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -107,7 +107,10 @@
     } else {
         k = key;
     }
-    LOGD("m_keyPrefix=%s key=%s k=%s", m_keyPrefix.string(), key.string(), k.string());
+    if (true) {
+        LOGD("Writing entity: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), key.string(),
+                dataSize);
+    }
 
     entity_header_v1 header;
     ssize_t keyLen;
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index d65a457..4ad9b51 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -41,11 +41,42 @@
 #define MAGIC0 0x70616e53 // Snap
 #define MAGIC1 0x656c6946 // File
 
-#if 1 // TEST_BACKUP_HELPERS
+/*
+ * File entity data format (v1):
+ *
+ *   - 4-byte version number of the metadata, little endian (0x00000001 for v1)
+ *   - 12 bytes of metadata
+ *   - the file data itself
+ *
+ * i.e. a 16-byte metadata header followed by the raw file data.  If the
+ * restore code does not recognize the metadata version, it can still
+ * interpret the file data itself correctly.
+ *
+ * file_metadata_v1:
+ *
+ *   - 4 byte version number === 0x00000001 (little endian)
+ *   - 4-byte access mode (little-endian)
+ *   - undefined (8 bytes)
+ */
+
+struct file_metadata_v1 {
+    int version;
+    int mode;
+    int undefined_1;
+    int undefined_2;
+};
+
+const static int CURRENT_METADATA_VERSION = 1;
+
+#if 1
+#define LOGP(f, x...)
+#else
+#if TEST_BACKUP_HELPERS
 #define LOGP(f, x...) printf(f "\n", x)
 #else
 #define LOGP(x...) LOGD(x)
 #endif
+#endif
 
 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
 
@@ -181,29 +212,48 @@
 }
 
 static int
-write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
+write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
         char const* realFilename)
 {
-    LOGP("write_update_file %s (%s)\n", realFilename, key.string());
+    LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
 
     const int bufsize = 4*1024;
     int err;
     int amt;
     int fileSize;
     int bytesLeft;
+    file_metadata_v1 metadata;
 
     char* buf = (char*)malloc(bufsize);
     int crc = crc32(0L, Z_NULL, 0);
 
 
-    bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
+    fileSize = lseek(fd, 0, SEEK_END);
     lseek(fd, 0, SEEK_SET);
 
+    if (sizeof(metadata) != 16) {
+        LOGE("ERROR: metadata block is the wrong size!");
+    }
+
+    bytesLeft = fileSize + sizeof(metadata);
     err = dataStream->WriteEntityHeader(key, bytesLeft);
     if (err != 0) {
+        free(buf);
         return err;
     }
 
+    // store the file metadata first
+    metadata.version = tolel(CURRENT_METADATA_VERSION);
+    metadata.mode = tolel(mode);
+    metadata.undefined_1 = metadata.undefined_2 = 0;
+    err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
+    if (err != 0) {
+        free(buf);
+        return err;
+    }
+    bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
+
+    // now store the file content
     while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
         bytesLeft -= amt;
         if (bytesLeft < 0) {
@@ -211,6 +261,7 @@
         }
         err = dataStream->WriteEntityData(buf, amt);
         if (err != 0) {
+            free(buf);
             return err;
         }
     }
@@ -224,6 +275,7 @@
                 bytesLeft -= amt;
                 err = dataStream->WriteEntityData(buf, amt);
                 if (err != 0) {
+                    free(buf);
                     return err;
                 }
             }
@@ -233,7 +285,6 @@
     }
 
     free(buf);
-
     return NO_ERROR;
 }
 
@@ -241,11 +292,19 @@
 write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
 {
     int err;
+    struct stat st;
+
+    err = stat(realFilename, &st);
+    if (err < 0) {
+        return errno;
+    }
+
     int fd = open(realFilename, O_RDONLY);
     if (fd == -1) {
         return errno;
     }
-    err = write_update_file(dataStream, fd, key, realFilename);
+
+    err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
     close(fd);
     return err;
 }
@@ -266,7 +325,6 @@
     }
 
     free(buf);
-
     return crc;
 }
 
@@ -295,13 +353,13 @@
 
         err = stat(file, &st);
         if (err != 0) {
-            LOGW("Error stating file %s", file);
             r.deleted = true;
         } else {
             r.deleted = false;
             r.s.modTime_sec = st.st_mtime;
             r.s.modTime_nsec = 0; // workaround sim breakage
             //r.s.modTime_nsec = st.st_mtime_nsec;
+            r.s.mode = st.st_mode;
             r.s.size = st.st_size;
             // we compute the crc32 later down below, when we already have the file open.
 
@@ -349,13 +407,13 @@
                 g.s.crc32 = compute_crc32(fd);
 
                 LOGP("%s", q.string());
-                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x",
-                        f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
-                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x",
-                        g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
+                LOGP("  new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
+                        f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
+                LOGP("  old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
+                        g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
                 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
-                        || f.size != g.s.size || f.crc32 != g.s.crc32) {
-                    write_update_file(dataStream, fd, p, g.file.string());
+                        || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
+                    write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
                 }
 
                 close(fd);
@@ -389,6 +447,7 @@
 RestoreHelperBase::RestoreHelperBase()
 {
     m_buf = malloc(RESTORE_BUF_SIZE);
+    m_loggedUnknownMetadata = false;
 }
 
 RestoreHelperBase::~RestoreHelperBase()
@@ -415,8 +474,25 @@
         return err;
     }
 
-    // TODO: World readable/writable for now.
-    mode = 0666;
+    // Get the metadata block off the head of the file entity and use that to
+    // set up the output file
+    file_metadata_v1 metadata;
+    amt = in->ReadEntityData(&metadata, sizeof(metadata));
+    if (amt != sizeof(metadata)) {
+        LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
+                (long)amt, strerror(errno));
+        return EIO;
+    }
+    metadata.version = fromlel(metadata.version);
+    metadata.mode = fromlel(metadata.mode);
+    if (metadata.version > CURRENT_METADATA_VERSION) {
+        if (!m_loggedUnknownMetadata) {
+            m_loggedUnknownMetadata = true;
+            LOGW("Restoring file with unsupported metadata version %d (currently %d)",
+                    metadata.version, CURRENT_METADATA_VERSION);
+        }
+    }
+    mode = metadata.mode;
 
     // Write the file and compute the crc
     crc = crc32(0L, Z_NULL, 0);
@@ -450,6 +526,7 @@
     r.s.modTime_sec = st.st_mtime;
     r.s.modTime_nsec = 0; // workaround sim breakage
     //r.s.modTime_nsec = st.st_mtime_nsec;
+    r.s.mode = st.st_mode;
     r.s.size = st.st_size;
     r.s.crc32 = crc;
 
@@ -536,6 +613,7 @@
         }
     }
 
+    free(contents);
     return contentsMatch && sizesMatch ? 0 : 1;
 }
 
@@ -623,6 +701,7 @@
 
     states[0].modTime_sec = 0xfedcba98;
     states[0].modTime_nsec = 0xdeadbeef;
+    states[0].mode = 0777; // decimal 511, hex 0x000001ff
     states[0].size = 0xababbcbc;
     states[0].crc32 = 0x12345678;
     states[0].nameLen = -12;
@@ -632,6 +711,7 @@
 
     states[1].modTime_sec = 0x93400031;
     states[1].modTime_nsec = 0xdeadbeef;
+    states[1].mode = 0666; // decimal 438, hex 0x000001b6
     states[1].size = 0x88557766;
     states[1].crc32 = 0x22334422;
     states[1].nameLen = -1;
@@ -641,6 +721,7 @@
 
     states[2].modTime_sec = 0x33221144;
     states[2].modTime_nsec = 0xdeadbeef;
+    states[2].mode = 0744; // decimal 484, hex 0x000001e4
     states[2].size = 0x11223344;
     states[2].crc32 = 0x01122334;
     states[2].nameLen = 0;
@@ -650,6 +731,7 @@
 
     states[3].modTime_sec = 0x33221144;
     states[3].modTime_nsec = 0xdeadbeef;
+    states[3].mode = 0755; // decimal 493, hex 0x000001ed
     states[3].size = 0x11223344;
     states[3].crc32 = 0x01122334;
     states[3].nameLen = 0;
@@ -669,35 +751,38 @@
     static const unsigned char correct_data[] = {
         // header
         0x53, 0x6e, 0x61, 0x70,  0x04, 0x00, 0x00, 0x00,
-        0x46, 0x69, 0x6c, 0x65,  0xac, 0x00, 0x00, 0x00,
+        0x46, 0x69, 0x6c, 0x65,  0xbc, 0x00, 0x00, 0x00,
 
         // bytes_of_padding
         0x98, 0xba, 0xdc, 0xfe,  0xef, 0xbe, 0xad, 0xde,
-        0xbc, 0xbc, 0xab, 0xab,  0x78, 0x56, 0x34, 0x12,
-        0x10, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,
+        0xff, 0x01, 0x00, 0x00,  0xbc, 0xbc, 0xab, 0xab,
+        0x78, 0x56, 0x34, 0x12,  0x10, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
 
         // bytes_of_padding3
         0x31, 0x00, 0x40, 0x93,  0xef, 0xbe, 0xad, 0xde,
-        0x66, 0x77, 0x55, 0x88,  0x22, 0x44, 0x33, 0x22,
-        0x11, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,  0x33, 0xab, 0xab, 0xab,
+        0xb6, 0x01, 0x00, 0x00,  0x66, 0x77, 0x55, 0x88,
+        0x22, 0x44, 0x33, 0x22,  0x11, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
+        0x33, 0xab, 0xab, 0xab,
 
         // bytes of padding2
         0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
-        0x44, 0x33, 0x22, 0x11,  0x34, 0x23, 0x12, 0x01,
-        0x12, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,  0x5f, 0x32, 0xab, 0xab,
+        0xe4, 0x01, 0x00, 0x00,  0x44, 0x33, 0x22, 0x11,
+        0x34, 0x23, 0x12, 0x01,  0x12, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
+        0x5f, 0x32, 0xab, 0xab,
 
         // bytes of padding3
         0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
-        0x44, 0x33, 0x22, 0x11,  0x34, 0x23, 0x12, 0x01,
-        0x13, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,  0x5f, 0x5f, 0x31, 0xab
+        0xed, 0x01, 0x00, 0x00,  0x44, 0x33, 0x22, 0x11,
+        0x34, 0x23, 0x12, 0x01,  0x13, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
+        0x5f, 0x5f, 0x31, 0xab
     };
 
     err = compare_file(filename, correct_data, sizeof(correct_data));
@@ -731,14 +816,14 @@
         const FileState state = readSnapshot.valueAt(i);
 
         if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
-                || states[i].modTime_nsec != state.modTime_nsec
+                || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
                 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
-            fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
-                            "          actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
-                    states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
-                    name.length(), filenames[i].string(),
-                    state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
-                    name.string());
+            fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
+                            "          actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
+                    states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
+                    states[i].crc32, name.length(), filenames[i].string(),
+                    state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
+                    state.nameLen, name.string());
             matched = false;
         }
     }
@@ -839,6 +924,7 @@
     size_t actualSize;
     bool done;
     int type;
+    ssize_t nRead;
 
     // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
 
@@ -873,8 +959,9 @@
         goto finished;
     }
 
-    err = reader.ReadEntityData(buf, bufSize);
-    if (err != NO_ERROR) {
+    nRead = reader.ReadEntityData(buf, bufSize);
+    if (nRead < 0) {
+        err = reader.Status();
         fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
         goto finished;
     }
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index e4f9f0f..7a33220 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -3919,7 +3919,7 @@
                         printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
                         continue;
                     }
-                    printf("      config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d\n",
+                    printf("      config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d lyt=%d\n",
                            (int)configIndex,
                            type->config.language[0] ? type->config.language[0] : '-',
                            type->config.language[1] ? type->config.language[1] : '-',
@@ -3932,7 +3932,8 @@
                            type->config.inputFlags,
                            type->config.navigation,
                            dtohs(type->config.screenWidth),
-                           dtohs(type->config.screenHeight));
+                           dtohs(type->config.screenHeight),
+                           type->config.screenLayout);
                     size_t entryCount = dtohl(type->entryCount);
                     uint32_t entriesStart = dtohl(type->entriesStart);
                     if ((entriesStart&0x3) != 0) {
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 5c8fcf2..edd1ea0 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -621,23 +621,37 @@
     }
 
     public void addListener(int uid) {
-        mClientUids.put(uid, 0);
-        if (mNavigating) {
-            try {
-                mBatteryStats.noteStartGps(uid);
-            } catch (RemoteException e) {
-                Log.w(TAG, "RemoteException in addListener");
+        synchronized(mListeners) {
+            if (mClientUids.indexOfKey(uid) >= 0) {
+                // Shouldn't be here -- already have this uid.
+                Log.w(TAG, "Duplicate add listener for uid " + uid);
+                return;
+            }
+            mClientUids.put(uid, 0);
+            if (mNavigating) {
+                try {
+                    mBatteryStats.noteStartGps(uid);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException in addListener");
+                }
             }
         }
     }
 
     public void removeListener(int uid) {
-        mClientUids.delete(uid);
-        if (mNavigating) {
-            try {
-                mBatteryStats.noteStopGps(uid);
-            } catch (RemoteException e) {
-                Log.w(TAG, "RemoteException in removeListener");
+        synchronized(mListeners) {
+            if (mClientUids.indexOfKey(uid) < 0) {
+                // Shouldn't be here -- don't have this uid.
+                Log.w(TAG, "Unneeded remove listener for uid " + uid);
+                return;
+            }
+            mClientUids.delete(uid);
+            if (mNavigating) {
+                try {
+                    mBatteryStats.noteStopGps(uid);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException in removeListener");
+                }
             }
         }
     }
@@ -836,30 +850,33 @@
     private void reportStatus(int status) {
         if (VERBOSE) Log.v(TAG, "reportStatus status: " + status);
 
-        boolean wasNavigating = mNavigating;
-        mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
-
-        if (wasNavigating != mNavigating) {
+        synchronized(mListeners) {
+            boolean wasNavigating = mNavigating;
+            mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
+    
+            if (wasNavigating == mNavigating) {
+                return;
+            }
+            
             if (mNavigating) {
                 if (DEBUG) Log.d(TAG, "Acquiring wakelock");
                  mWakeLock.acquire();
             }
-            synchronized(mListeners) {
-                int size = mListeners.size();
-                for (int i = 0; i < size; i++) {
-                    Listener listener = mListeners.get(i);
-                    try {
-                        if (mNavigating) {
-                            listener.mListener.onGpsStarted(); 
-                        } else {
-                            listener.mListener.onGpsStopped(); 
-                        }
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "RemoteException in reportStatus");
-                        mListeners.remove(listener);
-                        // adjust for size of list changing
-                        size--;
+        
+            int size = mListeners.size();
+            for (int i = 0; i < size; i++) {
+                Listener listener = mListeners.get(i);
+                try {
+                    if (mNavigating) {
+                        listener.mListener.onGpsStarted(); 
+                    } else {
+                        listener.mListener.onGpsStopped(); 
                     }
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException in reportStatus");
+                    mListeners.remove(listener);
+                    // adjust for size of list changing
+                    size--;
                 }
             }
 
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index 54ca6c4..e5ee9a3 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -50,12 +50,12 @@
      *
      * @see #ToneGenerator(int, int)
      */
-   public static final int TONE_DTMF_2 = 2;
-   /**
-    * DTMF tone for key 3: 1477Hz, 697Hz, continuous
-    *
-    * @see #ToneGenerator(int, int)
-    */
+    public static final int TONE_DTMF_2 = 2;
+    /**
+     * DTMF tone for key 3: 1477Hz, 697Hz, continuous
+     *
+     * @see #ToneGenerator(int, int)
+     */
     public static final int TONE_DTMF_3 = 3;
     /**
      * DTMF tone for key 4: 1209Hz, 770Hz, continuous
@@ -254,242 +254,474 @@
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_PIP = 33;
-
-
     /**
-     * CDMA SPECIFIC TONES START
-     */
-
-    /** TODO(Moto): Change "Proprietary" below with an appropriate specification reference */
-
-    /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     *  CDMA Dial tone : 425Hz  continuous
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
     public static final int TONE_CDMA_DIAL_TONE_LITE = 34;
-
-     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+    /**
+     * CDMA USA Ringback: 440Hz+480Hz 2s ON, 4000 OFF ...
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
     public static final int TONE_CDMA_NETWORK_USA_RINGBACK = 35;
-
     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     *  CDMA Intercept tone: 440Hz 250ms ON, 620Hz 250ms ON ...
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_REORDER = 36;
-
-   /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     *
-     * @see #ToneGenerator(int, int)
-     *
-     * @hide
-     */
-     public static final int TONE_CDMA_ABBR_REORDER = 37;
-
-   /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     *
-     * @see #ToneGenerator(int, int)
-     *
-     * @hide
-     */
-     public static final int TONE_CDMA_NETWORK_BUSY = 38;
-
-
-   /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     *
-     * @see #ToneGenerator(int, int)
-     *
-     * @hide
-     */
-    public static final int TONE_CDMA_ANSWER = 39;
-
-   /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     *
-     * @see #ToneGenerator(int, int)
-     *
-     * @hide
-     */
-    public static final int TONE_CDMA_NETWORK_CALLWAITING = 40;
-
-   /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     *
-     * @see #ToneGenerator(int, int)
-     *
-     * @hide
-     */
-    public static final int TONE_CDMA_PIP = 41;
-
-
+    public static final int TONE_CDMA_INTERCEPT = 36;
     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     * CDMA Abbr Intercept tone: 440Hz 250ms ON, 620Hz 250ms ON
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL = 42;
-
+    public static final int TONE_CDMA_ABBR_INTERCEPT = 37;
     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     * CDMA Reorder tone: 480Hz+620Hz 250ms ON, 250ms OFF...
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP = 43;
-
-     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     *
-     * @see #ToneGenerator(int, int)
-     *
-     * @hide
-     */
-    public static final int TONE_CDMA_CALL_SIGNAL_SP_PRI = 44;
-
+    public static final int TONE_CDMA_REORDER = 38;
     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
      *
+     * CDMA Abbr Reorder tone: 480Hz+620Hz 250ms ON, 250ms OFF repeated for 8 times
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT3 = 45;
-
+    public static final int TONE_CDMA_ABBR_REORDER = 39;
     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     * CDMA Network Busy tone: 480Hz+620Hz 500ms ON, 500ms OFF continuous
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_RING_RING = 46;
-
+    public static final int TONE_CDMA_NETWORK_BUSY = 40;
     /**
-     * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     * CDMA Confirm tone: 350Hz+440Hz 100ms ON, 100ms OFF repeated for 3 times
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT5 = 47;
-
+    public static final int TONE_CDMA_CONFIRM = 41;
     /**
-     * general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
      *
+     * CDMA answer tone: silent tone - defintion Frequency 0, 0ms ON, 0ms OFF
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT6 = 48;
-
+    public static final int TONE_CDMA_ANSWER = 42;
     /**
-     * general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
+     *
+     * CDMA Network Callwaiting tone: 440Hz 300ms ON
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_NETWORK_CALLWAITING = 43;
+    /**
+     * CDMA PIP tone: 480Hz 100ms ON, 100ms OFF repeated for 4 times
      *
      * @see #ToneGenerator(int, int)
-     *
-     * @hide
      */
-    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT7 = 49;
-
-    // TODO(Moto): Need comments for each one and we need ToneGenerator.cpp/ToneGenerator.h
-
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_L = 50;
-
-    /** @hide */
-    public static final int TONE_CDMA_LOW_L = 51;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_SS = 52;
-    /** @hide */
-    public static final int TONE_CDMA_MED_SS = 53;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_SS = 54;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_SSL = 55;
-
-
-    /** @hide */
-    public static final int TONE_CDMA_MED_SSL = 56;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_SSL = 57;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_SS_2 = 58;
-    /** @hide */
-    public static final int TONE_CDMA_MED_SS_2 = 59;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_SS_2 = 60;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_SLS = 61;
-    /** @hide */
-    public static final int TONE_CDMA_MED_SLS = 62;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_SLS = 63;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_S_X4 = 64;
-    /** @hide */
-    public static final int TONE_CDMA_MED_S_X4 = 65;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_S_X4 = 66;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_PBX_L = 67;
-    /** @hide */
-    public static final int TONE_CDMA_MED_PBX_L = 68;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_PBX_L = 69;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_PBX_SS = 70;
-    /** @hide */
-    public static final int TONE_CDMA_MED_PBX_SS = 71;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_PBX_SS = 72;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_PBX_SSL = 73;
-    /** @hide */
-    public static final int TONE_CDMA_MED_PBX_SSL = 74;
-
-    /** @hide */
-    public static final int TONE_CDMA_LOW_PBX_SSL = 75;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_PBX_SLS = 76;
-    /** @hide */
-    public static final int TONE_CDMA_MED_PBX_SLS = 77;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_PBX_SLS = 78;
-    /** @hide */
-    public static final int TONE_CDMA_HIGH_PBX_S_X4 = 79;
-    /** @hide */
-    public static final int TONE_CDMA_MED_PBX_S_X4 = 80;
-    /** @hide */
-    public static final int TONE_CDMA_LOW_PBX_S_X4 = 81;
-    /** @hide */
-    public static final int TONE_CDMA_INTERCEPT_ONE_SHOT = TONE_SUP_INTERCEPT_ABBREV;
-    /** @hide */
-    public static final int TONE_CDMA_REORDER_ONE_SHOT = TONE_CDMA_ABBR_REORDER;
-    /** @hide */
-    public static final int TONE_CDMA_NETWORK_BUSY_ONE_SHOT = 82;
-    /** @hide */
-    public static final int TONE_CDMA_ABBR_ALERT = 83;
-    /** @hide */
-    public static final int TONE_CDMA_SIGNAL_OFF = 84;
-    /** @hide */
-    public static final int TONE_CDMA_INVALID = 85;
+    public static final int TONE_CDMA_PIP = 44;
+    /**
+     *  ISDN Call Signal Normal tone: {2091Hz 32ms ON, 2556 64ms ON} 20 times,
+     *  2091 32ms ON, 2556 48ms ON, 4s OFF
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL = 45;
+    /**
+     *  ISDN Call Signal Intergroup tone: {2091Hz 32ms ON, 2556 64ms ON} 8 times,
+     * 2091Hz 32ms ON, 400ms OFF, {2091Hz 32ms ON, 2556Hz 64ms ON} times,
+     * 2091Hz 32ms ON, 4s OFF.
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP = 46;
+    /**
+     * ISDN Call Signal SP PRI tone:{2091Hz 32ms ON, 2556 64ms ON} 4 times
+     * 2091Hz 16ms ON, 200ms OFF, {2091Hz 32ms ON, 2556Hz 64ms ON} 4 times,
+     * 2091Hz 16ms ON, 200ms OFF
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI = 47;
+    /**
+     * ISDN Call sign PAT3 tone: silent tone
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT3 = 48;
+    /**
+     * ISDN Ping Ring tone: {2091Hz 32ms ON, 2556Hz 64ms ON} 5 times
+     * 2091Hz 20ms ON
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING = 49;
+    /**
+     *
+     * ISDN Pat5 tone: silent tone
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT5 = 50;
+    /**
+     *
+     * ISDN Pat6 tone: silent tone
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT6 = 51;
+    /**
+     * ISDN Pat7 tone: silent tone
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_CALL_SIGNAL_ISDN_PAT7 = 52;
+    /**
+     * TONE_CDMA_HIGH_L tone: {3700Hz 25ms, 4000Hz 25ms} 40 times
+     * 4000ms OFF, Repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_L = 53;
+    /**
+     * TONE_CDMA_MED_L tone: {2600Hz 25ms, 2900Hz 25ms} 40 times
+     * 4000ms OFF, Repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_L = 54;
+    /**
+     * TONE_CDMA_LOW_L tone: {1300Hz 25ms, 1450Hz 25ms} 40 times,
+     * 4000ms OFF, Repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_L = 55;
+    /**
+     * CDMA HIGH SS tone: {3700Hz 25ms, 4000Hz 25ms} repeat 16 times,
+     * 400ms OFF, repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_SS = 56;
+    /**
+     * CDMA MED SS tone: {2600Hz 25ms, 2900Hz 25ms} repeat 16 times,
+     * 400ms OFF, repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_SS = 57;
+    /**
+     * CDMA LOW SS tone: {1300z 25ms, 1450Hz 25ms} repeat 16 times,
+     * 400ms OFF, repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_SS = 58;
+    /**
+     * CDMA HIGH SSL tone: {3700Hz 25ms, 4000Hz 25ms} 8 times,
+     * 200ms OFF, {3700Hz 25ms, 4000Hz 25ms} repeat 8 times,
+     * 200ms OFF, {3700Hz 25ms, 4000Hz 25ms} repeat 16 times,
+     * 4000ms OFF, repeat ...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_SSL = 59;
+    /**
+     * CDMA MED SSL tone: {2600Hz 25ms, 2900Hz 25ms} 8 times,
+     * 200ms OFF, {2600Hz 25ms, 2900Hz 25ms} repeat 8 times,
+     * 200ms OFF, {2600Hz 25ms, 2900Hz 25ms} repeat 16 times,
+     * 4000ms OFF, repeat ...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_SSL = 60;
+    /**
+     * CDMA LOW SSL tone: {1300Hz 25ms, 1450Hz 25ms} 8 times,
+     * 200ms OFF, {1300Hz 25ms, 1450Hz 25ms} repeat 8 times,
+     * 200ms OFF, {1300Hz 25ms, 1450Hz 25ms} repeat 16 times,
+     * 4000ms OFF, repeat ...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_SSL = 61;
+    /**
+     * CDMA HIGH SS2 tone: {3700Hz 25ms, 4000Hz 25ms} 20 times,
+     * 1000ms OFF, {3700Hz 25ms, 4000Hz 25ms} 20 times,
+     * 3000ms OFF, repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_SS_2 = 62;
+    /**
+     * CDMA MED SS2 tone: {2600Hz 25ms, 2900Hz 25ms} 20 times,
+     * 1000ms OFF, {2600Hz 25ms, 2900Hz 25ms} 20 times,
+     * 3000ms OFF, repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_SS_2 = 63;
+    /**
+     * CDMA LOW SS2 tone: {1300Hz 25ms, 1450Hz 25ms} 20 times,
+     * 1000ms OFF, {1300Hz 25ms, 1450Hz 25ms} 20 times,
+     * 3000ms OFF, repeat ....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_SS_2 = 64;
+    /**
+     *  CDMA HIGH SLS tone: {3700Hz 25ms, 4000Hz 25ms} 10 times,
+     *  500ms OFF, {3700Hz 25ms, 4000Hz 25ms} 20 times, 500ms OFF,
+     *  {3700Hz 25ms, 4000Hz 25ms} 10 times, 3000ms OFF, REPEAT
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_SLS = 65;
+    /**
+     *  CDMA MED  SLS tone: {2600Hz 25ms, 2900Hz 25ms} 10 times,
+     *  500ms OFF, {2600Hz 25ms, 2900Hz 25ms} 20 times, 500ms OFF,
+     *  {2600Hz 25ms, 2900Hz 25ms} 10 times, 3000ms OFF, REPEAT
+     *
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_SLS = 66;
+    /**
+     *  CDMA LOW SLS tone: {1300Hz 25ms, 1450Hz 25ms} 10 times,
+     *  500ms OFF, {1300Hz 25ms, 1450Hz 25ms} 20 times, 500ms OFF,
+     *  {1300Hz 25ms, 1450Hz 25ms} 10 times, 3000ms OFF, REPEAT
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_SLS = 67;
+    /**
+     *  CDMA HIGH S X4 tone: {3700Hz 25ms, 4000Hz 25ms} 10 times,
+     *  500ms OFF, {3700Hz 25ms, 4000Hz 25ms} 10 times, 500ms OFF,
+     *  {3700Hz 25ms, 4000Hz 25ms} 10 times, 500ms OFF,
+     *  {3700Hz 25ms, 4000Hz 25ms} 10 times, 2500ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_S_X4 = 68;
+    /**
+     *  CDMA MED S X4 tone: {2600Hz 25ms, 2900Hz 25ms} 10 times,
+     *  500ms OFF, {2600Hz 25ms, 2900Hz 25ms} 10 times, 500ms OFF,
+     *  {2600Hz 25ms, 2900Hz 25ms} 10 times, 500ms OFF,
+     *  {2600Hz 25ms, 2900Hz 25ms} 10 times, 2500ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_S_X4 = 69;
+    /**
+     *  CDMA LOW  S X4 tone: {2600Hz 25ms, 2900Hz 25ms} 10 times,
+     *  500ms OFF, {2600Hz 25ms, 2900Hz 25ms} 10 times, 500ms OFF,
+     *  {2600Hz 25ms, 2900Hz 25ms} 10 times, 500ms OFF,
+     *  {2600Hz 25ms, 2900Hz 25ms} 10 times, 2500ms OFF, REPEAT....
+     *
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_S_X4 = 70;
+    /**
+     * CDMA HIGH PBX L: {3700Hz 25ms, 4000Hz 25ms}20 times,
+     * 2000ms OFF,  REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_PBX_L = 71;
+    /**
+     *  CDMA MED PBX L: {2600Hz 25ms, 2900Hz 25ms}20 times,
+     * 2000ms OFF,  REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_PBX_L = 72;
+    /**
+     * CDMA LOW PBX L: {1300Hz 25ms,1450Hz 25ms}20 times,
+     * 2000ms OFF,  REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_PBX_L = 73;
+    /**
+     * CDMA HIGH PBX SS tone: {3700Hz 25ms, 4000Hz 25ms} 8 times
+     * 200 ms OFF, {3700Hz 25ms 4000Hz 25ms}8 times,
+     * 2000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_PBX_SS = 74;
+    /**
+     * CDMA MED PBX SS tone: {2600Hz 25ms, 2900Hz 25ms} 8 times
+     * 200 ms OFF, {2600Hz 25ms 2900Hz 25ms}8 times,
+     * 2000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_PBX_SS = 75;
+    /**
+     * CDMA LOW PBX SS tone: {1300Hz 25ms, 1450Hz 25ms} 8 times
+     * 200 ms OFF, {1300Hz 25ms 1450Hz 25ms}8 times,
+     * 2000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_PBX_SS = 76;
+    /**
+     * CDMA HIGH PBX SSL tone:{3700Hz 25ms, 4000Hz 25ms} 8 times
+     * 200ms OFF, {3700Hz 25ms, 4000Hz 25ms} 8 times, 200ms OFF,
+     * {3700Hz 25ms, 4000Hz 25ms} 16 times, 1000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_PBX_SSL = 77;
+    /**
+     * CDMA MED PBX SSL tone:{2600Hz 25ms, 2900Hz 25ms} 8 times
+     * 200ms OFF, {2600Hz 25ms, 2900Hz 25ms} 8 times, 200ms OFF,
+     * {2600Hz 25ms, 2900Hz 25ms} 16 times, 1000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_PBX_SSL = 78;
+    /**
+     * CDMA LOW PBX SSL tone:{1300Hz 25ms, 1450Hz 25ms} 8 times
+     * 200ms OFF, {1300Hz 25ms, 1450Hz 25ms} 8 times, 200ms OFF,
+     * {1300Hz 25ms, 1450Hz 25ms} 16 times, 1000ms OFF, REPEAT....
+     *
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_PBX_SSL = 79;
+    /**
+     * CDMA HIGH PBX SSL tone:{3700Hz 25ms, 4000Hz 25ms} 8 times
+     * 200ms OFF, {3700Hz 25ms, 4000Hz 25ms} 16 times, 200ms OFF,
+     * {3700Hz 25ms, 4000Hz 25ms} 8 times, 1000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_PBX_SLS = 80;
+    /**
+     * CDMA HIGH PBX SLS tone:{2600Hz 25ms, 2900Hz 25ms} 8 times
+     * 200ms OFF, {2600Hz 25ms, 2900Hz 25ms} 16 times, 200ms OFF,
+     * {2600Hz 25ms, 2900Hz 25ms} 8 times, 1000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_PBX_SLS = 81;
+    /**
+     * CDMA HIGH PBX SLS tone:{1300Hz 25ms, 1450Hz 25ms} 8 times
+     * 200ms OFF, {1300Hz 25ms, 1450Hz 25ms} 16 times, 200ms OFF,
+     * {1300Hz 25ms, 1450Hz 25ms} 8 times, 1000ms OFF, REPEAT....
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_PBX_SLS = 82;
+    /**
+     * CDMA HIGH PBX X S4 tone: {3700Hz 25ms 4000Hz 25ms} 8 times,
+     * 200ms OFF, {3700Hz 25ms 4000Hz 25ms} 8 times, 200ms OFF,
+     * {3700Hz 25ms 4000Hz 25ms} 8 times, 200ms OFF,
+     * {3700Hz 25ms 4000Hz 25ms} 8 times, 800ms OFF, REPEAT...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_HIGH_PBX_S_X4 = 83;
+    /**
+     * CDMA MED PBX X S4 tone: {2600Hz 25ms 2900Hz 25ms} 8 times,
+     * 200ms OFF, {2600Hz 25ms 2900Hz 25ms} 8 times, 200ms OFF,
+     * {2600Hz 25ms 2900Hz 25ms} 8 times, 200ms OFF,
+     * {2600Hz 25ms 2900Hz 25ms} 8 times, 800ms OFF, REPEAT...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_MED_PBX_S_X4 = 84;
+    /**
+     * CDMA LOW PBX X S4 tone: {1300Hz 25ms 1450Hz 25ms} 8 times,
+     * 200ms OFF, {1300Hz 25ms 1450Hz 25ms} 8 times, 200ms OFF,
+     * {1300Hz 25ms 1450Hz 25ms} 8 times, 200ms OFF,
+     * {1300Hz 25ms 1450Hz 25ms} 8 times, 800ms OFF, REPEAT...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_LOW_PBX_S_X4 = 85;
+    /**
+     * CDMA Alert Network Lite tone: 1109Hz 62ms ON, 784Hz 62ms ON, 740Hz 62ms ON
+     * 622Hz 62ms ON, 1109Hz 62ms ON
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_ALERT_NETWORK_LITE = 86;
+    /**
+     * CDMA Alert Auto Redial tone: {1245Hz 62ms ON, 659Hz 62ms ON} 3 times,
+     * 1245 62ms ON
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_ALERT_AUTOREDIAL_LITE = 87;
+    /**
+     * CDMA One Min Beep tone: 1150Hz+770Hz 400ms ON
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_ONE_MIN_BEEP = 88;
+    /**
+     *
+     * CDMA KEYPAD Volume key lite tone: 941Hz+1477Hz 120ms ON
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_KEYPAD_VOLUME_KEY_LITE = 89;
+    /**
+     * CDMA PRESSHOLDKEY LITE tone: 587Hz 375ms ON, 1175Hz 125ms ON
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_PRESSHOLDKEY_LITE = 90;
+    /**
+     * CDMA ALERT INCALL LITE tone: 587Hz 62ms, 784 62ms, 831Hz 62ms,
+     * 784Hz 62ms, 1109 62ms, 784Hz 62ms, 831Hz 62ms, 784Hz 62ms
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_ALERT_INCALL_LITE = 91;
+    /**
+     * CDMA EMERGENCY RINGBACK tone: {941Hz 125ms ON, 10ms OFF} 3times
+     * 4990ms OFF, REPEAT...
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_EMERGENCY_RINGBACK = 92;
+    /**
+     * CDMA ALERT CALL GUARD tone: {1319Hz 125ms ON, 125ms OFF} 3 times
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_ALERT_CALL_GUARD = 93;
+    /**
+     * CDMA SOFT ERROR LITE  tone: 1047Hz 125ms ON, 370Hz 125ms
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_SOFT_ERROR_LITE = 94;
+    /**
+     * CDMA CALLDROP LITE tone: 1480Hz 125ms, 1397Hz 125ms, 784Hz 125ms
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_CALLDROP_LITE = 95;
+    /**
+     * CDMA_NETWORK_BUSY_ONE_SHOT tone: 425Hz 500ms ON, 500ms OFF.
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_NETWORK_BUSY_ONE_SHOT = 96;
+    /**
+     * CDMA_ABBR_ALERT tone: 1150Hz+770Hz 400ms ON
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int    TONE_CDMA_ABBR_ALERT = 97;
+    /**
+     * CDMA_SIGNAL_OFF - silent tone
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_CDMA_SIGNAL_OFF = 98;
 
     /** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
     public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
@@ -546,6 +778,71 @@
      * <li>{@link #TONE_SUP_CONGESTION_ABBREV}
      * <li>{@link #TONE_SUP_CONFIRM}
      * <li>{@link #TONE_SUP_PIP}
+     * <li>{@link #TONE_CDMA_DIAL_TONE_LITE}
+     * <li>{@link #TONE_CDMA_NETWORK_USA_RINGBACK}
+     * <li>{@link #TONE_CDMA_INTERCEPT}
+     * <li>{@link #TONE_CDMA_ABBR_INTERCEPT}
+     * <li>{@link #TONE_CDMA_REORDER}
+     * <li>{@link #TONE_CDMA_ABBR_REORDER}
+     * <li>{@link #TONE_CDMA_NETWORK_BUSY}
+     * <li>{@link #TONE_CDMA_CONFIRM}
+     * <li>{@link #TONE_CDMA_ANSWER}
+     * <li>{@link #TONE_CDMA_NETWORK_CALLWAITING}
+     * <li>{@link #TONE_CDMA_PIP}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_PAT3}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_PAT5}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_PAT6}
+     * <li>{@link #TONE_CDMA_CALL_SIGNAL_ISDN_PAT7}
+     * <li>{@link #TONE_CDMA_HIGH_L}
+     * <li>{@link #TONE_CDMA_MED_L}
+     * <li>{@link #TONE_CDMA_LOW_L}
+     * <li>{@link #TONE_CDMA_HIGH_SS}
+     * <li>{@link #TONE_CDMA_MED_SS}
+     * <li>{@link #TONE_CDMA_LOW_SS}
+     * <li>{@link #TONE_CDMA_HIGH_SSL}
+     * <li>{@link #TONE_CDMA_MED_SSL}
+     * <li>{@link #TONE_CDMA_LOW_SSL}
+     * <li>{@link #TONE_CDMA_HIGH_SS_2}
+     * <li>{@link #TONE_CDMA_MED_SS_2}
+     * <li>{@link #TONE_CDMA_LOW_SS_2}
+     * <li>{@link #TONE_CDMA_HIGH_SLS}
+     * <li>{@link #TONE_CDMA_MED_SLS}
+     * <li>{@link #TONE_CDMA_LOW_SLS}
+     * <li>{@link #TONE_CDMA_HIGH_S_X4}
+     * <li>{@link #TONE_CDMA_MED_S_X4}
+     * <li>{@link #TONE_CDMA_LOW_S_X4}
+     * <li>{@link #TONE_CDMA_HIGH_PBX_L}
+     * <li>{@link #TONE_CDMA_MED_PBX_L}
+     * <li>{@link #TONE_CDMA_LOW_PBX_L}
+     * <li>{@link #TONE_CDMA_HIGH_PBX_SS}
+     * <li>{@link #TONE_CDMA_MED_PBX_SS}
+     * <li>{@link #TONE_CDMA_LOW_PBX_SS}
+     * <li>{@link #TONE_CDMA_HIGH_PBX_SSL}
+     * <li>{@link #TONE_CDMA_MED_PBX_SSL}
+     * <li>{@link #TONE_CDMA_LOW_PBX_SSL}
+     * <li>{@link #TONE_CDMA_HIGH_PBX_SLS}
+     * <li>{@link #TONE_CDMA_MED_PBX_SLS}
+     * <li>{@link #TONE_CDMA_LOW_PBX_SLS}
+     * <li>{@link #TONE_CDMA_HIGH_PBX_S_X4}
+     * <li>{@link #TONE_CDMA_MED_PBX_S_X4}
+     * <li>{@link #TONE_CDMA_LOW_PBX_S_X4}
+     * <li>{@link #TONE_CDMA_ALERT_NETWORK_LITE}
+     * <li>{@link #TONE_CDMA_ALERT_AUTOREDIAL_LITE}
+     * <li>{@link #TONE_CDMA_ONE_MIN_BEEP}
+     * <li>{@link #TONE_CDMA_KEYPAD_VOLUME_KEY_LITE}
+     * <li>{@link #TONE_CDMA_PRESSHOLDKEY_LITE}
+     * <li>{@link #TONE_CDMA_ALERT_INCALL_LITE}
+     * <li>{@link #TONE_CDMA_EMERGENCY_RINGBACK}
+     * <li>{@link #TONE_CDMA_ALERT_CALL_GUARD}
+     * <li>{@link #TONE_CDMA_SOFT_ERROR_LITE}
+     * <li>{@link #TONE_CDMA_CALLDROP_LITE}
+     * <li>{@link #TONE_CDMA_NETWORK_BUSY_ONE_SHOT}
+     * <li>{@link #TONE_CDMA_ABBR_ALERT}
+     * <li>{@link #TONE_CDMA_SIGNAL_OFF}
      * </ul>
      * @see #ToneGenerator(int, int)
     */
@@ -566,7 +863,7 @@
     private native final void native_setup(int streamType, int volume);
 
     private native final void native_finalize();
-    
+
     @Override
     protected void finalize() { native_finalize(); }
 
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 7bfeb83..0273a5a 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -41,7 +41,7 @@
 // ----------------------------------------------------------------------------
 
 // helper function to extract a native Camera object from a Camera Java object
-extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct camera_context_t** context);
+extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context);
 
 struct fields_t {
     jfieldID    context;
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 81ee92c..c22cd53 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -33,199 +33,720 @@
 
 // Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
 const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
-        { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }},
-                     { duration: 0 , waveFreq: { 0 }}},
+        { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }, 0, 0},
+                     { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_0
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_1
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_2
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_3
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_4
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_5
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_6
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_7
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_8
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_9
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_S
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_P
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_A
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                             // TONE_DTMF_B
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_C
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_DTMF_D
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_DIAL
-        { segments: { { duration: 500 , waveFreq: { 425, 0 }},
-                      { duration: 500, waveFreq: { 0 }},
-                         { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 500 , waveFreq: { 425, 0 }, 0, 0},
+                      { duration: 500, waveFreq: { 0 }, 0, 0},
+                         { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_BUSY
-        { segments: { { duration: 200, waveFreq: { 425, 0 } },
-                      { duration: 200, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_CONGESTION
-        { segments: { { duration: 200, waveFreq: { 425, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 0,
           repeatSegment: 0 },                              // TONE_SUP_RADIO_ACK
-        { segments: { { duration: 200, waveFreq: { 425, 0 }},
-                      { duration: 200, waveFreq: { 0 }},
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0},
+                      { duration: 200, waveFreq: { 0 }, 0, 0},
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 2,
           repeatSegment: 0 },                              // TONE_SUP_RADIO_NOTAVAIL
-        { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }},
-                      { duration: 1000, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }, 0, 0},
+                      { duration: 1000, waveFreq: { 0 }, 0, 0},
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_ERROR
-        { segments: { { duration: 200, waveFreq: { 425, 0 } },
-                      { duration: 600, waveFreq: { 0 } },
-                      { duration: 200, waveFreq: { 425, 0 } },
-                      { duration: 3000, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 600, waveFreq: { 0 }, 0, 0 },
+                      { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_CALL_WAITING
-        { segments: { { duration: 1000, waveFreq: { 425, 0 } },
-                      { duration: 4000, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 1000, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_RINGTONE
-        { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 0,
           repeatSegment: 0 },                              // TONE_PROP_BEEP
-        { segments: { { duration: 100, waveFreq: { 1200, 0 } },
-                      { duration: 100, waveFreq: { 0 }  },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 100, waveFreq: { 1200, 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 0 }, 0, 0  },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 1,
           repeatSegment: 0 },                              // TONE_PROP_ACK
-        { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 0,
           repeatSegment: 0 },                              // TONE_PROP_NACK
-        { segments: { { duration: 200, waveFreq: { 400, 1200, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 200, waveFreq: { 400, 1200, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 0,
           repeatSegment: 0 },                              // TONE_PROP_PROMPT
-        { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
-                      { duration: 200, waveFreq: { 0 } },
-                      { duration: 40, waveFreq: { 400, 1200, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 0,
           repeatSegment: 0 },                             // TONE_PROP_BEEP2
-        { segments: { { duration: 250, waveFreq: { 440, 0 } },
-                      { duration: 250, waveFreq: { 620, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0 }},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_SUP_INTERCEPT
-        { segments: { { duration: 250, waveFreq: { 440, 0 } },
-                      { duration: 250, waveFreq: { 620, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 7,
           repeatSegment: 0 },                             // TONE_SUP_INTERCEPT_ABBREV
-        { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
-                      { duration: 250, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 7,
           repeatSegment: 0 },                             // TONE_SUP_CONGESTION_ABBREV
-        { segments: { { duration: 100, waveFreq: { 350, 440, 0 } },
-                      { duration: 100, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 100, waveFreq: { 350, 440, 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 2,
           repeatSegment: 0 },                             // TONE_SUP_CONFIRM
-        { segments: { { duration: 100, waveFreq: { 480, 0 } },
-                      { duration: 100, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 100, waveFreq: { 480, 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: 3,
           repeatSegment: 0 },                              // TONE_SUP_PIP
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 }, 0, 0},
+                     { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_CDMA_DIAL_TONE_LITE
+        { segments: { { duration: 2000, waveFreq: { 440, 480, 0 }, 0, 0 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_CDMA_NETWORK_USA_RINGBACK
+        { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt:  ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                             // TONE_CDMA_INTERCEPT
+        { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt:  0,
+          repeatSegment: 0 },                             // TONE_CDMA_ABBR_INTERCEPT
+        { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_CDMA_REORDER
+        { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: 7,
+          repeatSegment: 0 },                              // TONE_CDMA_ABBR_REORDER
+        { segments: { { duration: 500, waveFreq: { 480, 620, 0 }, 0, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_CDMA_NETWORK_BUSY
+        { segments: { { duration: 100, waveFreq: { 350, 440, 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: 2,
+          repeatSegment: 0 },                              // TONE_CDMA_CONFIRM
+        { segments: { { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_CDMA_ANSWER
+        { segments: { { duration: 300, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_CDMA_NETWORK_CALLWAITING
+        { segments: { { duration: 100, waveFreq: { 480, 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
+          repeatCnt: 3,
+          repeatSegment: 0 },                              // TONE_CDMA_PIP
+
+        { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 64, waveFreq: { 2556, 0}, 19, 0},
+                      { duration: 32, waveFreq: { 2091, 0}, 0, 0},
+                      { duration: 48, waveFreq: { 2556, 0}, 0, 0},
+                      { duration: 4000, waveFreq: { 0 }, 0, 0},
+                      { duration: 0,  waveFreq: { 0 }, 0, 0}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL
+        { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 64, waveFreq: { 2556, 0}, 7, 0 },
+                      { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 400, waveFreq: { 0 }, 0, 0 },
+                      { duration: 32,  waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 64,  waveFreq: { 2556, 0}, 7, 4 },
+                      { duration: 32,  waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0,    waveFreq: { 0 }, 0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP
+        { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 64, waveFreq: { 2556, 0}, 3, 0 },
+                      { duration: 16, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 200, waveFreq: { 0 },     0, 0 },
+                      { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 64, waveFreq: { 2556, 0}, 3, 4 },
+                      { duration: 16, waveFreq: { 2091, 0}, 0, 0 },
+                      { duration: 200, waveFreq: { 0 },     0, 0 },
+                      { duration: 0,   waveFreq: { 0 },     0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI
+        { segments: { { duration: 0,  waveFreq: { 0 }, 0, 0} },
+           repeatCnt: 0,
+           repeatSegment: 0 },                            // TONE_CDMA_CALL_SIGNAL_ISDN_PAT3
+        { segments: { { duration: 32, waveFreq: { 2091, 0 }, 0, 0 },
+                      { duration: 64, waveFreq: { 2556, 0 }, 4, 0 },
+                      { duration: 20, waveFreq: { 2091, 0 }, 0, 0 },
+                      { duration: 0,  waveFreq: { 0 }      , 0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING
+        { segments: { { duration: 0,  waveFreq: { 0 }, 0, 0} },
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_CDMA_CALL_SIGNAL_ISDN_PAT5
+        { segments: { { duration: 0,  waveFreq: { 0 }, 0, 0} },
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_CDMA_CALL_SIGNAL_ISDN_PAT6
+        { segments: { { duration: 0,  waveFreq: { 0 }, 0, 0} },
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_CDMA_CALL_SIGNAL_ISDN_PAT7
+
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 39, 0 },
+                      { duration: 4000, waveFreq: { 0 },     0, 0 },
+                      { duration: 0,    waveFreq: { 0 },     0, 0 } },
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_L
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 39, 0 },
+                      { duration: 4000, waveFreq: { 0 },     0, 0 },
+                      { duration: 0,    waveFreq: { 0 },     0, 0 } },
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_L
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 39, 0 },
+                      { duration: 4000, waveFreq: { 0 },     0, 0 },
+                      { duration: 0,    waveFreq: { 0 },     0, 0 } },
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_L
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 15, 0 },
+                      { duration: 400, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 } },
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_SS
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 15, 0 },
+                      { duration: 400, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_SS
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 15, 0 },
+                      { duration: 400, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_SS
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 15, 6 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_SSL
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 15, 6 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_SSL
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 15, 6 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_SSL
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 19, 0 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 19, 3 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_SS_2
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 19, 0 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 19, 3 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_SS_2
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 19, 0 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 19, 3 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_SS_2
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 9, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 19, 3 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 9, 6 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_SLS
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 9, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 19, 3 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 9, 6 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_SLS
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 9, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 19, 3 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 9, 6 },
+                      { duration: 3000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_SLS
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 9, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 9, 3 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 9, 6 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 9, 9 },
+                      { duration: 2500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_S_X4
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 9, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 9, 3 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 9, 6 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 9, 9 },
+                      { duration: 2500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_S_X4
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 9, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 9, 3 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 9, 6 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 9, 9 },
+                      { duration: 2500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_S_X4
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 19, 0 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_PBX_L
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 19, 0 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_PBX_L
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 19, 0 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_PBX_L
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_PBX_SS
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_PBX_SS
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_PBX_SS
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 15, 6 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_PBX_SSL
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 15, 6 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_PBX_SSL
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 15, 6 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_PBX_SSL
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 15, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 6 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_PBX_SLS
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 15, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 6 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_PBX_SLS
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 15, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 6 },
+                      { duration: 1000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_PBX_SLS
+        { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 6 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 4000, 0 }, 7, 9 },
+                      { duration: 800, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_HIGH_PBX_S_X4
+        { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 6 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 2900, 0 }, 7, 9 },
+                      { duration: 800, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_MED_PBX_S_X4
+        { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 6 },
+                      { duration: 200, waveFreq: { 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
+                      { duration: 25, waveFreq: { 1450, 0 }, 7, 9 },
+                      { duration: 800, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                           // TONE_CDMA_LOW_PBX_S_X4
+
+        { segments: { { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 784, 0 },  0, 0 },
+                      { duration: 62, waveFreq: { 740, 0 },  0, 0 },
+                      { duration: 62, waveFreq: { 622, 0 },  0, 0 },
+                      { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
+                      { duration: 0,  waveFreq: { 0 },       0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_ALERT_NETWORK_LITE
+        { segments: { { duration: 62, waveFreq: { 1245, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 659, 0 },  2, 0 },
+                      { duration: 62, waveFreq: { 1245, 0 }, 0, 0 },
+                      { duration: 0,  waveFreq: { 0 },       0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_ALERT_AUTOREDIAL_LITE
+        { segments: { { duration: 400, waveFreq: { 1150, 770, 0 }, 0, 0 },
+                      { duration: 0,   waveFreq: { 0 },            0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_ONE_MIN_BEEP
+        { segments: { { duration: 120, waveFreq: { 941, 1477, 0 }, 0, 0 },
+                      { duration: 0,   waveFreq: { 0 },            0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_KEYPAD_VOLUME_KEY_LITE
+        { segments: { { duration: 375, waveFreq: { 587, 0 }, 0, 0 },
+                      { duration: 125, waveFreq: { 1175, 0 }, 0, 0 },
+                      { duration: 0,   waveFreq: { 0 },       0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_PRESSHOLDKEY_LITE
+        { segments: { { duration: 62, waveFreq: { 587, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 831, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 831, 0 }, 0, 0 },
+                      { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
+                      { duration: 0,  waveFreq: { 0 },      0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_CDMA_ALERT_INCALL_LITE
+        { segments: { { duration: 125, waveFreq: { 941, 0 }, 0, 0 },
+                      { duration: 10,  waveFreq: { 0 },      2, 0 },
+                      { duration: 4990, waveFreq: { 0 },     0, 0 },
+                      { duration: 0,    waveFreq: { 0 },     0, 0 } },
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                            // TONE_CDMA_EMERGENCY_RINGBACK
+        { segments: { { duration: 125, waveFreq: { 1319, 0 }, 0, 0 },
+                      { duration: 125, waveFreq: { 0 },       0, 0 },
+                      { duration: 0,   waveFreq: { 0 },       0, 0 } },
+          repeatCnt: 2,
+          repeatSegment: 0 },                            // TONE_CDMA_ALERT_CALL_GUARD
+        { segments: { { duration: 125, waveFreq: { 1047, 0 }, 0, 0 },
+                      { duration: 125, waveFreq: { 370,  0 }, 0, 0 },
+                      { duration: 0,   waveFreq: { 0 },       0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_SOFT_ERROR_LITE
+        { segments: { { duration: 125, waveFreq: { 1480, 0 }, 0, 0 },
+                      { duration: 125, waveFreq: { 1397, 0 }, 0, 0 },
+                      { duration: 125, waveFreq: { 784, 0 },  0, 0 },
+                      { duration: 0,   waveFreq: { 0 },       0, 0 } },
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_CALLDROP_LITE
+
+        { segments: { { duration: 500, waveFreq: { 425, 0 }, 0, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: 0,
+          repeatSegment: 0 },                           // TONE_CDMA_NETWORK_BUSY_ONE_SHOT
+        { segments: { { duration: 400, waveFreq: { 1150, 770 }, 0, 0 },
+                      { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: 0,
+          repeatSegment: 0 },                           // TONE_CDMA_ABBR_ALERT
+          { segments: { { duration: 0, waveFreq: { 0 }, 0, 0 }},
+          repeatCnt: 0,
+          repeatSegment: 0 },                            // TONE_CDMA_SIGNAL_OFF
+
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_ANSI_DIAL
-        { segments: { { duration: 500, waveFreq: { 480, 620, 0 } },
-                      { duration: 500, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 500, waveFreq: { 480, 620, 0 }, 0, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_ANSI_BUSY
-        { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
-                      { duration: 250, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
+                      { duration: 250, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_ANSI_CONGESTION
-        { segments: { { duration: 300, waveFreq: { 440, 0 } },
-                      { duration: 9700, waveFreq: { 0 } },
-                      { duration: 100, waveFreq: { 440, 0 } },
-                      { duration: 100, waveFreq: { 0 } },
-                      { duration: 100, waveFreq: { 440, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 300, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 9700, waveFreq: { 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 0 }, 0, 0 },
+                      { duration: 100, waveFreq: { 440, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 1 },                              // TONE_ANSI_CALL_WAITING
-        { segments: { { duration: 2000, waveFreq: { 440, 480, 0 } },
-                      { duration: 4000, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 2000, waveFreq: { 440, 480, 0 }, 0, 0 },
+                      { duration: 4000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_ANSI_RINGTONE
-        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_JAPAN_DIAL
-        { segments: { { duration: 500, waveFreq: { 400, 0 } },
-                      { duration: 500, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 500, waveFreq: { 400, 0 }, 0, 0 },
+                      { duration: 500, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_JAPAN_BUSY
-        { segments: { { duration: 1000, waveFreq: { 400, 0 } },
-                      { duration: 2000, waveFreq: { 0 } },
-                      { duration: 0 , waveFreq: { 0 }}},
+        { segments: { { duration: 1000, waveFreq: { 400, 0 }, 0, 0 },
+                      { duration: 2000, waveFreq: { 0 }, 0, 0 },
+                      { duration: 0 , waveFreq: { 0 }, 0, 0}},
           repeatCnt: ToneGenerator::TONEGEN_INF,
           repeatSegment: 0 },                              // TONE_JAPAN_RADIO_ACK
+
+
+
 };
 
 // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
@@ -529,9 +1050,9 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 void ToneGenerator::audioCallback(int event, void* user, void *info) {
-    
+
     if (event != AudioTrack::EVENT_MORE_DATA) return;
-    
+
     const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
     ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
     short *lpOut = buffer->i16;
@@ -549,12 +1070,12 @@
         unsigned int lGenSmp;
         unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
         bool lSignal = false;
- 
+
         lpToneGen->mLock.lock();
 
         // Update pcm frame count and end time (current time at the end of this process)
         lpToneGen->mTotalSmp += lReqSmp;
-    
+
         // Update tone gen state machine and select wave gen command
         switch (lpToneGen->mState) {
         case TONE_PLAYING:
@@ -562,13 +1083,13 @@
             break;
         case TONE_STARTING:
             LOGV("Starting Cbk");
-    
+
             lWaveCmd = WaveGenerator::WAVEGEN_START;
             break;
         case TONE_STOPPING:
         case TONE_RESTARTING:
             LOGV("Stop/restart Cbk");
-    
+
             lWaveCmd = WaveGenerator::WAVEGEN_STOP;
             lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
             break;
@@ -578,21 +1099,21 @@
             lNumSmp = 0;
             goto audioCallback_EndLoop;
         }
-        
-    
+
+
         // Exit if tone sequence is over
         if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
             if (lpToneGen->mState == TONE_PLAYING) {
-                lpToneGen->mState = TONE_STOPPING;            
+                lpToneGen->mState = TONE_STOPPING;
             }
             goto audioCallback_EndLoop;
         }
-    
+
         if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
             // Time to go to next sequence segment
-    
+
             LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
-    
+
             lGenSmp = lReqSmp;
 
             // If segment,  ON -> OFF transition : ramp volume down
@@ -609,25 +1130,49 @@
                 LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
             }
 
-            // Go to next segment
-            lpToneGen->mCurSegment++;
+            // check if we need to loop and loop for the reqd times
+            if (lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
+                if (lpToneGen->mLoopCounter < lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
+                    LOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+                          lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
+                          lpToneGen->mLoopCounter,
+                          lpToneGen->mCurSegment);
+                    lpToneGen->mCurSegment = lpToneDesc->segments[lpToneGen->mCurSegment].loopIndx;
+                    ++lpToneGen->mLoopCounter;
+                } else {
+                    // completed loop. go to next segment
+                    lpToneGen->mLoopCounter = 0;
+                    lpToneGen->mCurSegment++;
+                    LOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+                          lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
+                          lpToneGen->mLoopCounter,
+                          lpToneGen->mCurSegment);
+                }
+            } else {
+                lpToneGen->mCurSegment++;
+                LOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+                      lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
+                      lpToneGen->mLoopCounter,
+                      lpToneGen->mCurSegment);
+
+            }
 
             // Handle loop if last segment reached
             if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
                 LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
-    
+
                 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
                 if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
                     LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
-    
+
                     lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
                     if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
                         lWaveCmd = WaveGenerator::WAVEGEN_START;
                     }
-    
+
                     LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
                             (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
-    
+
                 } else {
                     lGenSmp = 0;
                     LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
@@ -644,11 +1189,11 @@
                     lGenSmp = 0;
                 }
             }
-    
+
             // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
             lpToneGen->mNextSegSmp
                     += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000;
-    
+
         } else {
             // Inside a segment keep tone ON or OFF
             if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) {
@@ -657,24 +1202,24 @@
                 lGenSmp = lReqSmp;  // If event segment, tone is currently ON
             }
         }
-    
+
         if (lGenSmp) {
             // If samples must be generated, call all active wave generators and acumulate waves in lpOut
             unsigned int lFreqIdx = 0;
             unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
-    
+
             while (lFrequency != 0) {
                 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
                 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
                 lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
             }
         }
-        
+
         lNumSmp -= lReqSmp;
         lpOut += lReqSmp;
-    
+
 audioCallback_EndLoop:
-    
+
         switch (lpToneGen->mState) {
         case TONE_RESTARTING:
             LOGV("Cbk restarting track\n");
@@ -694,7 +1239,7 @@
             LOGV("Cbk Stopping track\n");
             lSignal = true;
             lpToneGen->mpAudioTrack->stop();
-            
+
             // Force loop exit
             lNumSmp = 0;
             break;
@@ -765,6 +1310,7 @@
     mTotalSmp = 0;
     mCurSegment = 0;
     mCurCount = 0;
+    mLoopCounter = 0;
     if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
         mNextSegSmp = TONEGEN_INF;
     } else{
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
index 14fd6ce..7f0ef21 100644
--- a/media/libmediaplayerservice/VorbisPlayer.cpp
+++ b/media/libmediaplayerservice/VorbisPlayer.cpp
@@ -345,9 +345,6 @@
 {
     LOGV("reset\n");
     Mutex::Autolock l(mMutex);
-    if (mState != STATE_OPEN) {
-        return NO_ERROR;
-    }
     return reset_nosync();
 }
 
@@ -355,10 +352,13 @@
 status_t VorbisPlayer::reset_nosync()
 {
     // close file
-    ov_clear(&mVorbisFile); // this also closes the FILE
     if (mFile != NULL) {
-        LOGV("OOPS! Vorbis didn't close the file");
-        fclose(mFile);
+        ov_clear(&mVorbisFile); // this also closes the FILE
+        if (mFile != NULL) {
+            LOGV("OOPS! Vorbis didn't close the file");
+            fclose(mFile);
+            mFile = NULL;
+        }
     }
     mState = STATE_ERROR;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index dbf937c..69e93a1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -18,6 +18,11 @@
 
 import com.android.mediaframeworktest.MediaFrameworkTest;
 
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.Writer;
+
 import android.hardware.Camera;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
@@ -47,6 +52,8 @@
     private static final long WAIT_TIME_PLAYBACK = 60000;  // 6 second
     private static final String OUTPUT_FILE = "/sdcard/temp";
     private static final String OUTPUT_FILE_EXT = ".3gp";
+    private static final String MEDIA_STRESS_OUTPUT =
+        "/sdcard/mediaStressOutput.txt";
     
     public MediaRecorderStressTest() {
         super("com.android.mediaframeworktest", MediaFrameworkTest.class);
@@ -62,8 +69,14 @@
     public void testStressCamera() throws Exception {
         SurfaceHolder mSurfaceHolder;             
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+        File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
+        output.write("Camera start preview stress:\n");
+        output.write("Total number of loops:" + 
+                NUMBER_OF_CAMERA_STRESS_LOOPS + "\n");
         try {        
             Log.v(TAG, "Start preview");
+            output.write("No of loop: ");
             for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){
                 mCamera = Camera.open();
                 mCamera.setPreviewDisplay(mSurfaceHolder);
@@ -71,10 +84,13 @@
                 Thread.sleep(WAIT_TIME_CAMERA_TEST);
                 mCamera.stopPreview();
                 mCamera.release();
+                output.write(" ," + i);
             }
         } catch (Exception e) {
                 Log.v(TAG, e.toString());
         }
+        output.write("\n\n");
+        output.close();
     }
     
     //Test case for stressing the camera preview.
@@ -83,7 +99,13 @@
         String filename;
         SurfaceHolder mSurfaceHolder;             
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
-        try {    
+        File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
+        output.write("H263 video record- reset after prepare Stress test\n");
+        output.write("Total number of loops:" +
+                NUMBER_OF_RECORDER_STRESS_LOOPS + "\n");
+        try {
+            output.write("No of loop: ");
             Log.v(TAG, "Start preview");
             for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){
                 Log.v(TAG, "counter = " + i);
@@ -106,10 +128,13 @@
                 Thread.sleep(WAIT_TIME_RECORDER_TEST);  
                 mRecorder.reset();
                 mRecorder.release();
+                output.write(", " + i);
             }
         } catch (Exception e) {
                 Log.v(TAG, e.toString());
         }
+        output.write("\n\n");
+        output.close();
     }
     
     
@@ -119,8 +144,14 @@
         String filename;
         SurfaceHolder mSurfaceHolder;             
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+        File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
+        output.write("Camera and video recorder preview switching\n");
+        output.write("Total number of loops:"
+                + NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n");
         try {    
             Log.v(TAG, "Start preview");
+            output.write("No of loop: ");
             for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){
                 mCamera = Camera.open();
                 mCamera.setPreviewDisplay(mSurfaceHolder);
@@ -147,11 +178,14 @@
                 Log.v(TAG, "before release");
                 Thread.sleep(WAIT_TIME_CAMERA_TEST);  
                 mRecorder.release();
-                Log.v(TAG, "release video recorder");                
+                Log.v(TAG, "release video recorder");
+                output.write(", " + i);
             }
         } catch (Exception e) {
                 Log.v(TAG, e.toString());
         }
+        output.write("\n\n");
+        output.close();
     }
     
     //Stress test case for record a video and play right away.
@@ -160,7 +194,13 @@
         String filename;
         SurfaceHolder mSurfaceHolder;             
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
-        try {    
+        File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
+        output.write("Video record and play back stress test:\n");
+        output.write("Total number of loops:"
+                + NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS + "\n");
+        try {
+            output.write("No of loop: ");
             for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
@@ -189,10 +229,13 @@
                 mp.start();
                 Thread.sleep(WAIT_TIME_PLAYBACK);
                 mp.release();
+                output.write(", " + i);
             }
         } catch (Exception e) {
                 Log.v(TAG, e.toString());
         }
+        output.write("\n\n");
+        output.close();
     }   
 }
 
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 25e31ee..de323b3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1052,23 +1052,25 @@
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;    
     
+    EGLSurface impl_draw = EGL_NO_SURFACE;
+    EGLSurface impl_read = EGL_NO_SURFACE;
     egl_context_t * const c = get_context(ctx);
     if (draw != EGL_NO_SURFACE) {
         egl_surface_t const * d = get_surface(draw);
         if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
         if (d->impl != c->impl)
             return setError(EGL_BAD_MATCH, EGL_FALSE);
-        draw = d->surface;
+        impl_draw = d->surface;
     }
     if (read != EGL_NO_SURFACE) {
         egl_surface_t const * r = get_surface(read);
         if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
         if (r->impl != c->impl)
             return setError(EGL_BAD_MATCH, EGL_FALSE);
-        read = r->surface;
+        impl_read = r->surface;
     }
     EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
-            dp->dpys[c->impl], draw, read, c->context);
+            dp->dpys[c->impl], impl_draw, impl_read, c->context);
 
     if (result == EGL_TRUE) {
         setGlThreadSpecific(c->cnx->hooks);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b2f3557..660b469 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -592,6 +592,21 @@
         loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                 R.integer.def_screen_off_timeout);
 
+        // Set default cdma emergency tone
+        loadSetting(stmt, Settings.System.EMERGENCY_TONE, 0);
+
+        // Set default cdma call auto retry
+        loadSetting(stmt, Settings.System.CALL_AUTO_RETRY, 0);
+
+        // Set default cdma DTMF type
+        loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);
+
+        // Set default hearing aid
+        loadSetting(stmt, Settings.System.HEARING_AID, 0);
+
+        // Set default tty mode
+        loadSetting(stmt, Settings.System.TTY_MODE, 0);
+
         loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
                 R.bool.def_airplane_mode_on);
 
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 54d038a..27c0021 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+#define LOG_NDEBUG 0
 
 #include <stdio.h>
 #include <unistd.h>
@@ -168,7 +168,7 @@
 static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
                            AudioSystem::audio_format format, int channel,
                            int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
-    LOGI("ttsSynthDoneCallback: %d bytes", bufferSize);
+    LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
 
     if (userdata == NULL){
         LOGE("userdata == NULL");
@@ -178,7 +178,7 @@
     SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
 
     if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
-        LOGI("Direct speech");
+        LOGV("Direct speech");
 
         if (wav == NULL) {
             delete pForAfter;
@@ -189,26 +189,34 @@
             prepAudioTrack(pJniData, rate, format, channel);
             if (pJniData->mAudioOut) {
                 pJniData->mAudioOut->write(wav, bufferSize);
-                LOGI("AudioTrack wrote: %d bytes", bufferSize);
+                //LOGV("AudioTrack wrote: %d bytes", bufferSize);
             } else {
-                LOGI("Can't play, null audiotrack");
+                LOGE("Can't play, null audiotrack");
             }
         }
     } else  if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
-        LOGI("Save to file");
+        LOGV("Save to file");
         if (wav == NULL) {
             delete pForAfter;
-            LOGI("Null: speech has completed");
+            LOGV("Null: speech has completed");
         }
         if (bufferSize > 0){
             fwrite(wav, 1, bufferSize, pForAfter->outputFile);
         }
     }
-    // TODO update to call back into the SynthProxy class through the
+    // Future update:
+    //      For sync points in the speech, call back into the SynthProxy class through the
     //      javaTTSFields.synthProxyMethodPost methode to notify
-    //      playback has completed if the synthesis is done, i.e.
-    //      if status == TTS_SYNTH_DONE
-    //delete pForAfter;
+    //      playback has completed if the synthesis is done or if a marker has been reached.
+
+    if (status == TTS_SYNTH_DONE) {
+        // this struct was allocated in the original android_tts_SynthProxy_speak call,
+        // all processing matching this call is now done.
+        LOGV("Speech synthesis done.");
+        delete pForAfter;
+        pForAfter = NULL;
+        return TTS_CALLBACK_HALT;
+    }
 
     // we don't update the wav (output) parameter as we'll let the next callback
     // write at the same location, we've consumed the data already, but we need
@@ -289,14 +297,38 @@
                 variantNativeString);
     }
     env->ReleaseStringUTFChars(language, langNativeString);
-    env->ReleaseStringUTFChars(language, countryNativeString);
-    env->ReleaseStringUTFChars(language, variantNativeString);
+    env->ReleaseStringUTFChars(country, countryNativeString);
+    env->ReleaseStringUTFChars(variant, variantNativeString);
+}
+
+
+static void
+android_tts_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData,
+        jstring language, jstring country, jstring variant)
+{
+    if (jniData == 0) {
+        LOGE("android_tts_SynthProxy_loadLanguage(): invalid JNI data");
+        return;
+    }
+
+    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
+    const char *langNativeString = env->GetStringUTFChars(language, 0);
+    const char *countryNativeString = env->GetStringUTFChars(country, 0);
+    const char *variantNativeString = env->GetStringUTFChars(variant, 0);
+    // TODO check return codes
+    if (pSynthData->mNativeSynthInterface) {
+        pSynthData->mNativeSynthInterface->loadLanguage(langNativeString, countryNativeString,
+                variantNativeString);
+    }
+    env->ReleaseStringUTFChars(language, langNativeString);
+    env->ReleaseStringUTFChars(country, countryNativeString);
+    env->ReleaseStringUTFChars(variant, variantNativeString);
 }
 
 
 static void
 android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData,
-        int speechRate)
+        jint speechRate)
 {
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_setSpeechRate(): invalid JNI data");
@@ -316,6 +348,28 @@
 }
 
 
+static void
+android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData,
+        jint pitch)
+{
+    if (jniData == 0) {
+        LOGE("android_tts_SynthProxy_setPitch(): invalid JNI data");
+        return;
+    }
+
+    int bufSize = 10;
+    char buffer [bufSize];
+    sprintf(buffer, "%d", pitch);
+
+    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
+    LOGI("setting pitch to %d", pitch);
+    // TODO check return codes
+    if (pSynthData->mNativeSynthInterface) {
+        pSynthData->mNativeSynthInterface->setProperty("pitch", buffer, bufSize);
+    }
+}
+
+
 // TODO: Refactor this to get rid of any assumptions about sample rate, etc.
 static void
 android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,
@@ -493,7 +547,8 @@
     memset(buf, 0, bufSize);
     // TODO check return codes
     if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->getLanguage(buf, &bufSize);
+        // TODO use the correct getLanguage()
+        //pSynthData->mNativeSynthInterface->getLanguage(buf, &bufSize);
     }
     return env->NewStringUTF(buf);
 }
@@ -537,10 +592,18 @@
         "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
         (void*)android_tts_SynthProxy_setLanguage
     },
+    {   "native_loadLanguage",
+        "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+        (void*)android_tts_SynthProxy_loadLanguage
+    },
     {   "native_setSpeechRate",
         "(II)V",
         (void*)android_tts_SynthProxy_setSpeechRate
     },
+    {   "native_setPitch",
+        "(II)V",
+        (void*)android_tts_SynthProxy_setPitch
+    },
     {   "native_playAudioBuffer",
         "(III)V",
         (void*)android_tts_SynthProxy_playAudioBuffer
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index 364dc58..a8eaaa43 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -73,6 +73,13 @@
     public void setLanguage(String language, String country, String variant) {
         native_setLanguage(mJniData, language, country, variant);
     }
+    
+    /**
+     * Loads the language: it's not set, but prepared for use later.
+     */
+    public void loadLanguage(String language, String country, String variant) {
+        native_loadLanguage(mJniData, language, country, variant);
+    }
 
     /**
      * Sets the speech rate
@@ -81,6 +88,12 @@
         native_setSpeechRate(mJniData, speechRate);
     }
 
+    /**
+     * Sets the pitch of the synthesized voice
+     */
+    public final void setPitch(int pitch) {
+        native_setPitch(mJniData, pitch);
+    }
 
     /**
      * Plays the given audio buffer
@@ -143,8 +156,13 @@
 
     private native final void native_setLanguage(int jniData, String language, String country,
             String variant);
+    
+    private native final void native_loadLanguage(int jniData, String language, String country,
+            String variant);
 
     private native final void native_setSpeechRate(int jniData, int speechRate);
+    
+    private native final void native_setPitch(int jniData, int speechRate);
 
     // TODO add buffer format
     private native final void native_playAudioBuffer(int jniData, int bufferPointer, int bufferSize);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index e9c4ab7..c6b5bee 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -47,12 +47,13 @@
 public class TtsService extends Service implements OnCompletionListener {
 
     private static class SpeechItem {
-        public static final int SPEECH = 0;
-        public static final int EARCON = 1;
-        public static final int SILENCE = 2;
+        public static final int TEXT = 0;
+        public static final int IPA = 1;
+        public static final int EARCON = 2;
+        public static final int SILENCE = 3;
         public String mText = null;
         public ArrayList<String> mParams = null;
-        public int mType = SPEECH;
+        public int mType = TEXT;
         public long mDuration = 0;
 
         public SpeechItem(String text, ArrayList<String> params, int itemType) {
@@ -89,6 +90,9 @@
         }
     }
 
+    private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
+    private static final int MAX_FILENAME_LENGTH = 250;
+
     private static final String ACTION = "android.intent.action.USE_TTS";
     private static final String CATEGORY = "android.intent.category.TTS";
     private static final String PKGNAME = "android.tts";
@@ -108,7 +112,6 @@
     private final ReentrantLock synthesizerLock = new ReentrantLock();
 
     private SynthProxy nativeSynth;
-
     @Override
     public void onCreate() {
         super.onCreate();
@@ -145,14 +148,11 @@
 
 
     private void setDefaultSettings() {
-
         // TODO handle default language
         setLanguage("eng", "USA", "");
 
         // speech rate
         setSpeechRate(getDefaultRate());
-
-        // TODO handle default pitch
     }
 
 
@@ -171,6 +171,39 @@
     }
 
 
+    private String getDefaultLanguage() {
+        String defaultLang = android.provider.Settings.Secure.getString(mResolver,
+                android.provider.Settings.Secure.TTS_DEFAULT_LANG);
+        if (defaultLang == null) {
+            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
+        } else {
+            return defaultLang;
+        }
+    }
+
+
+    private String getDefaultCountry() {
+        String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
+                android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
+        if (defaultCountry == null) {
+            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
+        } else {
+            return defaultCountry;
+        }
+    }
+
+
+    private String getDefaultLocVariant() {
+        String defaultVar = android.provider.Settings.Secure.getString(mResolver,
+                android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
+        if (defaultVar == null) {
+            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+        } else {
+            return defaultVar;
+        }
+    }
+
+
     private void setSpeechRate(int rate) {
         if (isDefaultEnforced()) {
             nativeSynth.setSpeechRate(getDefaultRate());
@@ -179,16 +212,23 @@
         }
     }
 
+
+    private void setPitch(int pitch) {
+        nativeSynth.setPitch(pitch);
+    }
+
+
     private void setLanguage(String lang, String country, String variant) {
-        Log.v("TTS", "TtsService.setLanguage("+lang+", "+country+", "+variant+")");
+        Log.v("TTS", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
         if (isDefaultEnforced()) {
-            nativeSynth.setLanguage(lang, country, variant);
+            nativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
+                    getDefaultLocVariant());
         } else {
-            // TODO handle default language
-            nativeSynth.setLanguage("eng", "USA", "");
+            nativeSynth.setLanguage(lang, country, variant);
         }
     }
 
+
     /**
      * Adds a sound resource to the TTS.
      *
@@ -259,7 +299,29 @@
         if (queueMode == 0) {
             stop();
         }
-        mSpeechQueue.add(new SpeechItem(text, params, SpeechItem.SPEECH));
+        mSpeechQueue.add(new SpeechItem(text, params, SpeechItem.TEXT));
+        if (!mIsSpeaking) {
+            processSpeechQueue();
+        }
+    }
+
+    /**
+     * Speaks the given IPA text using the specified queueing mode and parameters.
+     *
+     * @param ipaText
+     *            The IPA text that should be spoken
+     * @param queueMode
+     *            0 for no queue (interrupts all previous utterances), 1 for
+     *            queued
+     * @param params
+     *            An ArrayList of parameters. This is not implemented for all
+     *            engines.
+     */
+    private void speakIpa(String ipaText, int queueMode, ArrayList<String> params) {
+        if (queueMode == 0) {
+            stop();
+        }
+        mSpeechQueue.add(new SpeechItem(ipaText, params, SpeechItem.IPA));
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
@@ -353,6 +415,26 @@
                         synth.start();
                         return;
                     }
+                    if (params != null){
+                        String language = "";
+                        String country = "";
+                        String variant = "";
+                        for (int i = 0; i < params.size() - 1; i = i + 2){
+                            String param = params.get(i);
+                            if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)){
+                                setSpeechRate(Integer.parseInt(params.get(i+1)));
+                            } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){
+                                language = params.get(i+1);
+                            } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){
+                                country = params.get(i+1);
+                            } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){
+                                variant = params.get(i+1);
+                            }
+                        }
+                        if (language.length() > 0){
+                            setLanguage(language, country, variant);
+                        }
+                    }
                     nativeSynth.speak(text);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
@@ -363,6 +445,7 @@
                     if (synthAvailable) {
                         synthesizerLock.unlock();
                     }
+                    processSpeechQueue();
                 }
             }
         }
@@ -384,6 +467,11 @@
         return sr;
     }
 
+    private void broadcastTtsQueueProcessingCompleted(){
+        Intent i = new Intent(Intent.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
+        sendBroadcast(i);
+    }
+
     private void dispatchSpeechCompletedCallbacks(String mark) {
         Log.i("TTS callback", "dispatch started");
         // Broadcast to all clients the new value.
@@ -400,6 +488,33 @@
         Log.i("TTS callback", "dispatch completed to " + N);
     }
 
+    private SpeechItem splitCurrentTextIfNeeded(SpeechItem currentSpeechItem){
+        if (currentSpeechItem.mText.length() < MAX_SPEECH_ITEM_CHAR_LENGTH){
+            return currentSpeechItem;
+        } else {
+            ArrayList<SpeechItem> splitItems = new ArrayList<SpeechItem>();
+            int start = 0;
+            int end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
+            String splitText;
+            SpeechItem splitItem;
+            while (end < currentSpeechItem.mText.length()){
+                splitText = currentSpeechItem.mText.substring(start, end);
+                splitItem = new SpeechItem(splitText, null, SpeechItem.TEXT);
+                splitItems.add(splitItem);
+                start = end;
+                end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
+            }
+            splitText = currentSpeechItem.mText.substring(start);
+            splitItem = new SpeechItem(splitText, null, SpeechItem.TEXT);
+            splitItems.add(splitItem);
+            mSpeechQueue.remove(0);
+            for (int i = splitItems.size() - 1; i >= 0; i--){
+                mSpeechQueue.add(0, splitItems.get(i));
+            }
+            return mSpeechQueue.get(0);
+        }
+    }
+
     private void processSpeechQueue() {
         boolean speechQueueAvailable = false;
         try {
@@ -409,11 +524,7 @@
             }
             if (mSpeechQueue.size() < 1) {
                 mIsSpeaking = false;
-                // Dispatch a completion here as this is the
-                // only place where speech completes normally.
-                // Nothing left to say in the queue is a special case
-                // that is always a "mark" - associated text is null.
-                dispatchSpeechCompletedCallbacks("");
+                broadcastTtsQueueProcessingCompleted();
                 return;
             }
 
@@ -424,11 +535,12 @@
             // processSpeechQueue to continue running the queue
             Log.i("TTS processing: ", currentSpeechItem.mText);
             if (sr == null) {
-                if (currentSpeechItem.mType == SpeechItem.SPEECH) {
-                    // TODO: Split text up into smaller chunks before accepting
-                    // them for processing.
+                if (currentSpeechItem.mType == SpeechItem.TEXT) {
+                    currentSpeechItem = splitCurrentTextIfNeeded(currentSpeechItem);
                     speakInternalOnly(currentSpeechItem.mText,
                             currentSpeechItem.mParams);
+                } else if (currentSpeechItem.mType == SpeechItem.IPA) {
+                    // TODO Implement IPA support
                 } else {
                     // This is either silence or an earcon that was missing
                     silence(currentSpeechItem.mDuration);
@@ -494,8 +606,7 @@
     }
 
     /**
-     * Synthesizes the given text using the specified queuing mode and
-     * parameters.
+     * Synthesizes the given text to a file using the specified parameters.
      *
      * @param text
      *            The String of text that should be synthesized
@@ -524,8 +635,7 @@
                 return false;
             }
             // Don't allow a filename that is too long
-            // TODO use platform constant
-            if (filename.length() > 250) {
+            if (filename.length() > MAX_FILENAME_LENGTH) {
                 return false;
             }
             nativeSynth.synthesizeToFile(text, filename);
@@ -540,6 +650,51 @@
         return true;
     }
 
+    /**
+     * Synthesizes the given IPA text to a file using the specified parameters.
+     *
+     * @param ipaText
+     *            The String of IPA text that should be synthesized
+     * @param params
+     *            An ArrayList of parameters. The first element of this array
+     *            controls the type of voice to use.
+     * @param filename
+     *            The string that gives the full output filename; it should be
+     *            something like "/sdcard/myappsounds/mysound.wav".
+     * @return A boolean that indicates if the synthesis succeeded
+     */
+    private boolean synthesizeIpaToFile(String ipaText, ArrayList<String> params,
+            String filename, boolean calledFromApi) {
+        // Only stop everything if this is a call made by an outside app trying
+        // to
+        // use the API. Do NOT stop if this is a call from within the service as
+        // clearing the speech queue here would be a mistake.
+        if (calledFromApi) {
+            stop();
+        }
+        Log.i("TTS", "Synthesizing IPA to " + filename);
+        boolean synthAvailable = false;
+        try {
+            synthAvailable = synthesizerLock.tryLock();
+            if (!synthAvailable) {
+                return false;
+            }
+            // Don't allow a filename that is too long
+            if (filename.length() > MAX_FILENAME_LENGTH) {
+                return false;
+            }
+            // TODO: Add nativeSynth.synthesizeIpaToFile(text, filename);
+        } finally {
+            // This check is needed because finally will always run; even if the
+            // method returns somewhere in the try block.
+            if (synthAvailable) {
+                synthesizerLock.unlock();
+            }
+        }
+        Log.i("TTS", "Completed synthesis for " + filename);
+        return true;
+    }
+
     @Override
     public IBinder onBind(Intent intent) {
         if (ACTION.equals(intent.getAction())) {
@@ -586,6 +741,27 @@
         }
 
         /**
+         * Speaks the given IPA text using the specified queueing mode and
+         * parameters.
+         *
+         * @param ipaText
+         *            The IPA text that should be spoken
+         * @param queueMode
+         *            0 for no queue (interrupts all previous utterances), 1 for
+         *            queued
+         * @param params
+         *            An ArrayList of parameters. The first element of this
+         *            array controls the type of voice to use.
+         */
+        public void speakIpa(String ipaText, int queueMode, String[] params) {
+            ArrayList<String> speakingParams = new ArrayList<String>();
+            if (params != null) {
+                speakingParams = new ArrayList<String>(Arrays.asList(params));
+            }
+            mSelf.speakIpa(ipaText, queueMode, speakingParams);
+        }
+
+        /**
          * Plays the earcon using the specified queueing mode and parameters.
          *
          * @param earcon
@@ -706,6 +882,17 @@
         }
 
         /**
+         * Sets the pitch for the TTS. Note that this will only have an
+         * effect on synthesized speech; it will not affect pre-recorded speech.
+         *
+         * @param pitch
+         *            The pitch that should be used for the synthesized voice
+         */
+        public void setPitch(int pitch) {
+            mSelf.setPitch(pitch);
+        }
+
+        /**
          * Sets the speech rate for the TTS, which affects the synthesized voice.
          *
          * @param lang  the three letter ISO language code.
@@ -717,7 +904,7 @@
         }
 
         /**
-         * Speaks the given text using the specified queueing mode and
+         * Synthesizes the given text to a file using the specified
          * parameters.
          *
          * @param text
@@ -738,6 +925,29 @@
             }
             return mSelf.synthesizeToFile(text, speakingParams, filename, true);
         }
+
+        /**
+         * Synthesizes the given IPA text to a file using the specified
+         * parameters.
+         *
+         * @param ipaText
+         *            The String of IPA text that should be synthesized
+         * @param params
+         *            An ArrayList of parameters. The first element of this
+         *            array controls the type of voice to use.
+         * @param filename
+         *            The string that gives the full output filename; it should
+         *            be something like "/sdcard/myappsounds/mysound.wav".
+         * @return A boolean that indicates if the synthesis succeeded
+         */
+        public boolean synthesizeIpaToFile(String ipaText, String[] params,
+                String filename) {
+            ArrayList<String> speakingParams = new ArrayList<String>();
+            if (params != null) {
+                speakingParams = new ArrayList<String>(Arrays.asList(params));
+            }
+            return mSelf.synthesizeIpaToFile(ipaText, speakingParams, filename, true);
+        }
     };
 
 }
diff --git a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
index a12db8c..2ad218f 100644
--- a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index 8358c5c..877fa6b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
@@ -25,8 +25,7 @@
  * The service that manages the L2TP-over-IPSec VPN connection.
  */
 class L2tpIpsecService extends VpnService<L2tpIpsecProfile> {
-    private static final String IPSEC_SERVICE = "racoon";
-    private static final String L2TP_SERVICE = "mtpd";
+    private static final String IPSEC_DAEMON = "racoon";
 
     @Override
     protected void connect(String serverIp, String username, String password)
@@ -34,7 +33,7 @@
         String hostIp = getHostIp();
 
         // IPSEC
-        AndroidServiceProxy ipsecService = startService(IPSEC_SERVICE);
+        AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON);
         ipsecService.sendCommand(
                 String.format("SETKEY %s %s", hostIp, serverIp));
         ipsecService.sendCommand(String.format("SET_CERTS %s %s %s %s",
@@ -42,11 +41,11 @@
                 getUserkeyPath()));
 
         // L2TP
-        AndroidServiceProxy l2tpService = startService(L2TP_SERVICE);
-        l2tpService.sendCommand2("l2tp", serverIp, "1701", "",
-                    "file", getPppOptionFilePath(),
-                    "name", username,
-                    "password", password);
+        L2tpIpsecProfile p = getProfile();
+        MtpdHelper.sendCommand(this, L2tpService.L2TP_DAEMON, serverIp,
+                L2tpService.L2TP_PORT,
+                (p.isSecretEnabled() ? p.getSecretString() : null),
+                username, password);
     }
 
     private String getCaCertPath() {
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
index 9aad7a1..9273f35 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
@@ -24,19 +24,15 @@
  * The service that manages the L2TP VPN connection.
  */
 class L2tpService extends VpnService<L2tpProfile> {
-    private static final String L2TP_SERVICE = "mtpd";
+    static final String L2TP_DAEMON = "l2tp";
+    static final String L2TP_PORT = "1701";
 
     @Override
     protected void connect(String serverIp, String username, String password)
             throws IOException {
-        String hostIp = getHostIp();
-
-        // L2TP
-        AndroidServiceProxy l2tpService = startService(L2TP_SERVICE);
-        l2tpService.sendCommand2("l2tp", serverIp, "1701", "",
-                    "file", getPppOptionFilePath(),
-                    "name", username,
-                    "password", password);
+        L2tpProfile p = getProfile();
+        MtpdHelper.sendCommand(this, L2TP_DAEMON, serverIp, L2TP_PORT,
+                (p.isSecretEnabled() ? p.getSecretString() : null),
+                username, password);
     }
-
 }
diff --git a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
new file mode 100644
index 0000000..6160900
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.server.vpn;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * A helper class for sending commands to the MTP daemon (mtpd).
+ */
+class MtpdHelper {
+    private static final String MTPD_SERVICE = "mtpd";
+    private static final String VPN_LINKNAME = "vpn";
+    private static final String PPP_ARGS_SEPARATOR = "";
+
+    static void sendCommand(VpnService<?> vpnService, String protocol,
+            String serverIp, String port, String secret, String username,
+            String password) throws IOException {
+        ArrayList<String> args = new ArrayList<String>();
+        args.addAll(Arrays.asList(protocol, serverIp, port));
+        if (secret != null) args.add(secret);
+        args.add(PPP_ARGS_SEPARATOR);
+        addPppArguments(vpnService, args, serverIp, username, password);
+
+        AndroidServiceProxy mtpd = vpnService.startService(MTPD_SERVICE);
+        mtpd.sendCommand2(args.toArray(new String[args.size()]));
+    }
+
+    private static void addPppArguments(VpnService<?> vpnService,
+            ArrayList<String> args, String serverIp, String username,
+            String password) throws IOException {
+        args.addAll(Arrays.asList(
+                "linkname", VPN_LINKNAME,
+                "name", username,
+                "password", password,
+                "ipparam", serverIp + "@" + vpnService.getGatewayIp(),
+                "refuse-eap", "nodefaultroute", "usepeerdns",
+                "idle", "1800",
+                "mtu", "1400",
+                "mru", "1400"));
+    }
+
+    private MtpdHelper() {
+    }
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java b/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java
index f20d85f..f0bbc34 100644
--- a/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/packages/VpnServices/src/com/android/server/vpn/PptpService.java b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
new file mode 100644
index 0000000..01362a5
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.server.vpn;
+
+import android.net.vpn.PptpProfile;
+
+import java.io.IOException;
+
+/**
+ * The service that manages the PPTP VPN connection.
+ */
+class PptpService extends VpnService<PptpProfile> {
+    static final String PPTP_DAEMON = "pptp";
+    static final String PPTP_PORT = "1723";
+    @Override
+    protected void connect(String serverIp, String username, String password)
+            throws IOException {
+        MtpdHelper.sendCommand(this, PPTP_DAEMON, serverIp, PPTP_PORT, null,
+                username, password);
+    }
+
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java b/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java
index 14d7521..50fbf4b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index fdefe9c..44127ff 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
@@ -20,6 +20,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.net.NetworkUtils;
 import android.net.vpn.VpnManager;
 import android.net.vpn.VpnProfile;
 import android.net.vpn.VpnState;
@@ -31,8 +32,10 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 
 /**
@@ -153,16 +156,25 @@
     }
 
     /**
-     * Returns the IP of the specified host name.
+     * Returns the IP address of the specified host name.
      */
     protected String getIp(String hostName) throws IOException {
-        InetAddress iaddr = InetAddress.getByName(hostName);
-        byte[] aa = iaddr.getAddress();
-        StringBuilder sb = new StringBuilder().append(byteToInt(aa[0]));
-        for (int i = 1; i < aa.length; i++) {
-            sb.append(".").append(byteToInt(aa[i]));
+        return InetAddress.getByName(hostName).getHostAddress();
+    }
+
+    /**
+     * Returns the IP address of the default gateway.
+     */
+    protected String getGatewayIp() throws IOException {
+        Enumeration<NetworkInterface> ifces =
+                NetworkInterface.getNetworkInterfaces();
+        for (; ifces.hasMoreElements(); ) {
+            NetworkInterface ni = ifces.nextElement();
+            int gateway = NetworkUtils.getDefaultRoute(ni.getName());
+            if (gateway == 0) continue;
+            return toInetAddress(gateway).getHostAddress();
         }
-        return sb.toString();
+        throw new IOException("Default gateway is not available");
     }
 
     /**
@@ -170,7 +182,7 @@
      * connection is established.
      */
     protected String getConnectMonitorFile() {
-        return "/etc/ppp/ip-up";
+        return "/etc/ppp/ip-up-vpn";
     }
 
     /**
@@ -461,12 +473,18 @@
     }
 
     private String reallyGetHostIp() throws IOException {
-        Socket s = new Socket();
-        s.connect(new InetSocketAddress("www.google.com", 80), DNS_TIMEOUT);
-        String ipAddress = s.getLocalAddress().getHostAddress();
-        Log.d(TAG, "Host IP: " + ipAddress);
-        s.close();
-        return ipAddress;
+        Enumeration<NetworkInterface> ifces =
+                NetworkInterface.getNetworkInterfaces();
+        for (; ifces.hasMoreElements(); ) {
+            NetworkInterface ni = ifces.nextElement();
+            int gateway = NetworkUtils.getDefaultRoute(ni.getName());
+            if (gateway == 0) continue;
+            Enumeration<InetAddress> addrs = ni.getInetAddresses();
+            for (; addrs.hasMoreElements(); ) {
+                return addrs.nextElement().getHostAddress();
+            }
+        }
+        throw new IOException("Host IP is not available");
     }
 
     private String getProfileSubpath(String subpath) throws IOException {
@@ -496,8 +514,13 @@
         return ((message == null) || (message.length() == 0));
     }
 
-    private static int byteToInt(byte b) {
-        return ((int) b) & 0x0FF;
+    private InetAddress toInetAddress(int addr) throws IOException {
+        byte[] aa = new byte[4];
+        for (int i= 0; i < aa.length; i++) {
+            aa[i] = (byte) (addr & 0x0FF);
+            addr >>= 8;
+        }
+        return InetAddress.getByAddress(aa);
     }
 
     private class ServiceHelper implements ProcessProxy.Callback {
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 7195ea61..63fc858 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 197404e..c67f0b5 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -34,7 +34,6 @@
 import android.content.pm.Signature;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -43,12 +42,13 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.SparseArray;
 
 import android.backup.IBackupManager;
+import android.backup.IRestoreObserver;
 import android.backup.IRestoreSession;
-import android.backup.BackupManager;
 import android.backup.RestoreSet;
 
 import com.android.internal.backup.LocalTransport;
@@ -60,7 +60,6 @@
 import java.io.EOFException;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.RandomAccessFile;
@@ -68,16 +67,19 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 class BackupManagerService extends IBackupManager.Stub {
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
 
+    // Persistent properties
+    private static final String BACKUP_TRANSPORT_PROPERTY = "persist.service.bkup.trans";
+    private static final String BACKUP_ENABLED_PROPERTY = "persist.service.bkup.enabled";
+
     // Default time to wait after data changes before we back up the data
-    private static final long COLLECTION_INTERVAL = 1000;
-    //private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
+    private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
 
     private static final int MSG_RUN_BACKUP = 1;
     private static final int MSG_RUN_FULL_BACKUP = 2;
@@ -88,10 +90,11 @@
 
     private Context mContext;
     private PackageManager mPackageManager;
-    private final IActivityManager mActivityManager;
+    private IActivityManager mActivityManager;
+    private boolean mEnabled;   // access to this is synchronized on 'this'
     private final BackupHandler mBackupHandler = new BackupHandler();
     // map UIDs to the set of backup client services within that UID's app set
-    private SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
+    private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
         = new SparseArray<HashSet<ApplicationInfo>>();
     // set of backup services that have pending changes
     private class BackupRequest {
@@ -110,8 +113,8 @@
     // Backups that we haven't started yet.
     private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
             = new HashMap<ApplicationInfo,BackupRequest>();
-    // Do we need to back up the package manager metadata on the next pass?
-    private boolean mDoPackageManager;
+
+    // Pseudoname that we use for the Package Manager metadata "package"
     private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
 
     // locking around the pending-backup management
@@ -129,12 +132,27 @@
     private final Object mClearDataLock = new Object();
     private volatile boolean mClearingData;
 
-    // Current active transport & restore session
-    private int mTransportId;
+    // Transport bookkeeping
+    private final HashMap<String,IBackupTransport> mTransports
+            = new HashMap<String,IBackupTransport>();
+    private String mCurrentTransport;
     private IBackupTransport mLocalTransport, mGoogleTransport;
     private RestoreSession mActiveRestoreSession;
 
-    private File mStateDir;
+    private class RestoreParams {
+        public IBackupTransport transport;
+        public IRestoreObserver observer;
+        public long token;
+
+        RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
+            transport = _transport;
+            observer = _obs;
+            token = _token;
+        }
+    }
+
+    // Where we keep our journal files and other bookkeeping
+    private File mBaseStateDir;
     private File mDataDir;
     private File mJournalDir;
     private File mJournal;
@@ -146,13 +164,15 @@
         mActivityManager = ActivityManagerNative.getDefault();
 
         // Set up our bookkeeping
-        mStateDir = new File(Environment.getDataDirectory(), "backup");
-        mStateDir.mkdirs();
+        // !!! STOPSHIP: make this disabled by default so that we then gate on
+        //               setupwizard or other opt-out UI
+        mEnabled = SystemProperties.getBoolean(BACKUP_ENABLED_PROPERTY, true);
+        mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
         mDataDir = Environment.getDownloadCacheDirectory();
 
         // Set up the backup-request journaling
-        mJournalDir = new File(mStateDir, "pending");
-        mJournalDir.mkdirs();
+        mJournalDir = new File(mBaseStateDir, "pending");
+        mJournalDir.mkdirs();   // creates mBaseStateDir along the way
         makeJournalLocked();    // okay because no other threads are running yet
 
         // Build our mapping of uid to backup client services.  This implicitly
@@ -165,12 +185,19 @@
         // Set up our transport options and initialize the default transport
         // TODO: Have transports register themselves somehow?
         // TODO: Don't create transports that we don't need to?
-        mTransportId = BackupManager.TRANSPORT_LOCAL;
-        //mTransportId = BackupManager.TRANSPORT_GOOGLE;
         mLocalTransport = new LocalTransport(context);  // This is actually pretty cheap
-        mGoogleTransport = null;
+        ComponentName localName = new ComponentName(context, LocalTransport.class);
+        registerTransport(localName.flattenToShortString(), mLocalTransport);
 
-        // Attach to the Google backup transport.
+        mGoogleTransport = null;
+        // !!! TODO: set up the default transport name "the right way"
+        mCurrentTransport = SystemProperties.get(BACKUP_TRANSPORT_PROPERTY,
+                "com.google.android.backup/.BackupTransportService");
+        if (DEBUG) Log.v(TAG, "Starting with transport " + mCurrentTransport);
+
+        // Attach to the Google backup transport.  When this comes up, it will set
+        // itself as the current transport because we explicitly reset mCurrentTransport
+        // to null.
         Intent intent = new Intent().setComponent(new ComponentName(
                 "com.google.android.backup",
                 "com.google.android.backup.BackupTransportService"));
@@ -229,6 +256,13 @@
         }
     }
 
+    // Add a transport to our set of available backends
+    private void registerTransport(String name, IBackupTransport transport) {
+        synchronized (mTransports) {
+            mTransports.put(name, transport);
+        }
+    }
+
     // ----- Track installation/removal of packages -----
     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
@@ -274,11 +308,13 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.v(TAG, "Connected to Google transport");
             mGoogleTransport = IBackupTransport.Stub.asInterface(service);
+            registerTransport(name.flattenToShortString(), mGoogleTransport);
         }
 
         public void onServiceDisconnected(ComponentName name) {
             if (DEBUG) Log.v(TAG, "Disconnected from Google transport");
             mGoogleTransport = null;
+            registerTransport(name.flattenToShortString(), null);
         }
     };
 
@@ -290,7 +326,7 @@
             switch (msg.what) {
             case MSG_RUN_BACKUP:
             {
-                IBackupTransport transport = getTransport(mTransportId);
+                IBackupTransport transport = getTransport(mCurrentTransport);
                 if (transport == null) {
                     Log.v(TAG, "Backup requested but no transport available");
                     break;
@@ -337,9 +373,8 @@
 
             case MSG_RUN_RESTORE:
             {
-                int token = msg.arg1;
-                IBackupTransport transport = (IBackupTransport)msg.obj;
-                (new PerformRestoreThread(transport, token)).start();
+                RestoreParams params = (RestoreParams)msg.obj;
+                (new PerformRestoreThread(params.transport, params.observer, params.token)).start();
                 break;
             }
             }
@@ -351,29 +386,29 @@
     void addPackageParticipantsLocked(String packageName) {
         // Look for apps that define the android:backupAgent attribute
         if (DEBUG) Log.v(TAG, "addPackageParticipantsLocked: " + packageName);
-        List<ApplicationInfo> targetApps = allAgentApps();
+        List<PackageInfo> targetApps = allAgentPackages();
         addPackageParticipantsLockedInner(packageName, targetApps);
     }
 
     private void addPackageParticipantsLockedInner(String packageName,
-            List<ApplicationInfo> targetApps) {
+            List<PackageInfo> targetPkgs) {
         if (DEBUG) {
-            Log.v(TAG, "Adding " + targetApps.size() + " backup participants:");
-            for (ApplicationInfo a : targetApps) {
-                Log.v(TAG, "    " + a + " agent=" + a.backupAgentName);
+            Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
+            for (PackageInfo p : targetPkgs) {
+                Log.v(TAG, "    " + p + " agent=" + p.applicationInfo.backupAgentName
+                        + " uid=" + p.applicationInfo.uid);
             }
         }
 
-        for (ApplicationInfo app : targetApps) {
-            if (packageName == null || app.packageName.equals(packageName)) {
-                int uid = app.uid;
+        for (PackageInfo pkg : targetPkgs) {
+            if (packageName == null || pkg.packageName.equals(packageName)) {
+                int uid = pkg.applicationInfo.uid;
                 HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
                 if (set == null) {
                     set = new HashSet<ApplicationInfo>();
                     mBackupParticipants.put(uid, set);
                 }
-                set.add(app);
-                backUpPackageManagerData();
+                set.add(pkg.applicationInfo);
             }
         }
     }
@@ -382,67 +417,66 @@
     // 'packageName' is null, *all* participating apps will be removed.
     void removePackageParticipantsLocked(String packageName) {
         if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
-        List<ApplicationInfo> allApps = null;
+        List<PackageInfo> allApps = null;
         if (packageName != null) {
-            allApps = new ArrayList<ApplicationInfo>();
+            allApps = new ArrayList<PackageInfo>();
             try {
-                ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, 0);
-                allApps.add(app);
+                int flags = PackageManager.GET_SIGNATURES;
+                allApps.add(mPackageManager.getPackageInfo(packageName, flags));
             } catch (Exception e) {
-                // just skip it
+                // just skip it (???)
             }
         } else {
             // all apps with agents
-            allApps = allAgentApps();
+            allApps = allAgentPackages();
         }
         removePackageParticipantsLockedInner(packageName, allApps);
     }
 
     private void removePackageParticipantsLockedInner(String packageName,
-            List<ApplicationInfo> agents) {
+            List<PackageInfo> agents) {
         if (DEBUG) {
             Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
                     + ") removing " + agents.size() + " entries");
-            for (ApplicationInfo a : agents) {
-                Log.v(TAG, "    - " + a);
+            for (PackageInfo p : agents) {
+                Log.v(TAG, "    - " + p);
             }
         }
-        for (ApplicationInfo app : agents) {
-            if (packageName == null || app.packageName.equals(packageName)) {
-                int uid = app.uid;
+        for (PackageInfo pkg : agents) {
+            if (packageName == null || pkg.packageName.equals(packageName)) {
+                int uid = pkg.applicationInfo.uid;
                 HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
                 if (set != null) {
                     // Find the existing entry with the same package name, and remove it.
                     // We can't just remove(app) because the instances are different.
                     for (ApplicationInfo entry: set) {
-                        if (entry.packageName.equals(app.packageName)) {
+                        if (entry.packageName.equals(pkg.packageName)) {
                             set.remove(entry);
-                            backUpPackageManagerData();
                             break;
                         }
                     }
                     if (set.size() == 0) {
-                        mBackupParticipants.delete(uid);                    }
+                        mBackupParticipants.delete(uid);
+                    }
                 }
             }
         }
     }
 
     // Returns the set of all applications that define an android:backupAgent attribute
-    private List<ApplicationInfo> allAgentApps() {
+    private List<PackageInfo> allAgentPackages() {
         // !!! TODO: cache this and regenerate only when necessary
-        List<ApplicationInfo> allApps = mPackageManager.getInstalledApplications(0);
-        int N = allApps.size();
-        if (N > 0) {
-            for (int a = N-1; a >= 0; a--) {
-                ApplicationInfo app = allApps.get(a);
-                if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
-                        || app.backupAgentName == null) {
-                    allApps.remove(a);
-                }
+        int flags = PackageManager.GET_SIGNATURES;
+        List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+        int N = packages.size();
+        for (int a = N-1; a >= 0; a--) {
+            ApplicationInfo app = packages.get(a).applicationInfo;
+            if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+                    || app.backupAgentName == null) {
+                packages.remove(a);
             }
         }
-        return allApps;
+        return packages;
     }
 
     // Reset the given package's known backup participants.  Unlike add/remove, the update
@@ -455,39 +489,32 @@
         if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
 
         // brute force but small code size
-        List<ApplicationInfo> allApps = allAgentApps();
+        List<PackageInfo> allApps = allAgentPackages();
         removePackageParticipantsLockedInner(packageName, allApps);
         addPackageParticipantsLockedInner(packageName, allApps);
     }
 
-    private void backUpPackageManagerData() {
-        // No need to schedule a backup just for the metadata; just piggyback on
-        // the next actual data backup.
-        synchronized(this) {
-            mDoPackageManager = true;
+    // The queue lock should be held when scheduling a backup pass
+    private void scheduleBackupPassLocked(long timeFromNowMillis) {
+        // We only schedule backups when we're actually enabled
+        synchronized (this) {
+            if (mEnabled) {
+                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
+                mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, timeFromNowMillis);
+            } else if (DEBUG) {
+                Log.v(TAG, "Disabled, so not scheduling backup pass");
+            }
         }
     }
 
-    // The queue lock should be held when scheduling a backup pass
-    private void scheduleBackupPassLocked(long timeFromNowMillis) {
-        mBackupHandler.removeMessages(MSG_RUN_BACKUP);
-        mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, timeFromNowMillis);
-    }
-
     // Return the given transport
-    private IBackupTransport getTransport(int transportID) {
-        switch (transportID) {
-        case BackupManager.TRANSPORT_LOCAL:
-            Log.v(TAG, "Supplying local transport");
-            return mLocalTransport;
-
-        case BackupManager.TRANSPORT_GOOGLE:
-            Log.v(TAG, "Supplying Google transport");
-            return mGoogleTransport;
-
-        default:
-            Log.e(TAG, "Asked for unknown transport " + transportID);
-            return null;
+    private IBackupTransport getTransport(String transportName) {
+        synchronized (mTransports) {
+            IBackupTransport transport = mTransports.get(transportName);
+            if (transport == null) {
+                Log.w(TAG, "Requested unavailable transport: " + transportName);
+            }
+            return transport;
         }
     }
 
@@ -530,6 +557,19 @@
 
     // clear an application's data, blocking until the operation completes or times out
     void clearApplicationDataSynchronous(String packageName) {
+        // Don't wipe packages marked allowClearUserData=false
+        try {
+            PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
+            if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
+                if (DEBUG) Log.i(TAG, "allowClearUserData=false so not wiping "
+                        + packageName);
+                return;
+            }
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Tried to clear data for " + packageName + " but not found");
+            return;
+        }
+
         ClearDataObserver observer = new ClearDataObserver();
 
         synchronized(mClearDataLock) {
@@ -565,6 +605,7 @@
         private static final String TAG = "PerformBackupThread";
         IBackupTransport mTransport;
         ArrayList<BackupRequest> mQueue;
+        File mStateDir;
         File mJournal;
 
         public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
@@ -572,52 +613,43 @@
             mTransport = transport;
             mQueue = queue;
             mJournal = journal;
+
+            try {
+                mStateDir = new File(mBaseStateDir, transport.transportDirName());
+            } catch (RemoteException e) {
+                // can't happen; the transport is local
+            }
+            mStateDir.mkdirs();
         }
 
         @Override
         public void run() {
             if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
 
-            // start up the transport
-            try {
-                mTransport.startSession();
-            } catch (Exception e) {
-                Log.e(TAG, "Error session transport");
-                e.printStackTrace();
-                return;
-            }
-
-            // The transport is up and running.  First, back up the package manager
-            // metadata if necessary
-            boolean doPackageManager;
-            synchronized (BackupManagerService.this) {
-                doPackageManager = mDoPackageManager;
-                mDoPackageManager = false;
-            }
-            if (doPackageManager) {
-                // The package manager doesn't have a proper <application> etc, but since
-                // it's running here in the system process we can just set up its agent
-                // directly and use a synthetic BackupRequest.
-                if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
-
-                PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
-                        mPackageManager, allAgentApps());
-                BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
-                pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
-                processOneBackup(pmRequest,
-                        IBackupAgent.Stub.asInterface(pmAgent.onBind()),
-                        mTransport);
-            }
+            // The package manager doesn't have a proper <application> etc, but since
+            // it's running here in the system process we can just set up its agent
+            // directly and use a synthetic BackupRequest.  We always run this pass
+            // because it's cheap and this way we guarantee that we don't get out of
+            // step even if we're selecting among various transports at run time.
+            PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+                    mPackageManager, allAgentPackages());
+            BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+            pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+            processOneBackup(pmRequest,
+                    IBackupAgent.Stub.asInterface(pmAgent.onBind()),
+                    mTransport);
 
             // Now run all the backups in our queue
             doQueuedBackups(mTransport);
 
             // Finally, tear down the transport
             try {
-                mTransport.endSession();
-            } catch (Exception e) {
-                Log.e(TAG, "Error ending transport");
-                e.printStackTrace();
+                if (!mTransport.finishBackup()) {
+                    // STOPSHIP TODO: handle errors
+                    Log.e(TAG, "Backup failure in finishBackup()");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in finishBackup()", e);
             }
 
             if (!mJournal.delete()) {
@@ -712,24 +744,18 @@
                     if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
                     backupData =
                         ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
-                    int error = transport.performBackup(packInfo, backupData);
+                    if (!transport.performBackup(packInfo, backupData)) {
+                        // STOPSHIP TODO: handle errors
+                        Log.e(TAG, "Backup failure in performBackup()");
+                    }
 
                     // !!! TODO: After successful transport, delete the now-stale data
                     // and juggle the files so that next time the new state is passed
                     //backupDataName.delete();
                     newStateName.renameTo(savedStateName);
                 }
-            } catch (NameNotFoundException e) {
-                Log.e(TAG, "Package not found on backup: " + packageName);
-            } catch (FileNotFoundException fnf) {
-                Log.w(TAG, "File not found on backup: ");
-                fnf.printStackTrace();
-            } catch (RemoteException e) {
-                Log.d(TAG, "Remote target " + request.appInfo.packageName + " threw during backup:");
-                e.printStackTrace();
             } catch (Exception e) {
-                Log.w(TAG, "Final exception guard in backup: ");
-                e.printStackTrace();
+                Log.e(TAG, "Error backing up " + packageName, e);
             }
         }
     }
@@ -737,25 +763,6 @@
 
     // ----- Restore handling -----
 
-    // Is the given package restorable on this device?  Returns the on-device app's
-    // ApplicationInfo struct if it is; null if not.
-    //
-    // !!! TODO: also consider signatures
-    PackageInfo isRestorable(PackageInfo packageInfo) {
-        if (packageInfo.packageName != null) {
-            try {
-                PackageInfo app = mPackageManager.getPackageInfo(packageInfo.packageName,
-                        PackageManager.GET_SIGNATURES);
-                if ((app.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
-                    return app;
-                }
-            } catch (Exception e) {
-                // doesn't exist on this device, or other error -- just ignore it.
-            }
-        }
-        return null;
-    }
-
     private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
         // Allow unsigned apps, but not signed on one device and unsigned on the other
         // !!! TODO: is this the right policy?
@@ -792,8 +799,10 @@
 
     class PerformRestoreThread extends Thread {
         private IBackupTransport mTransport;
-        private int mToken;
+        private IRestoreObserver mObserver;
+        private long mToken;
         private RestoreSet mImage;
+        private File mStateDir;
 
         class RestoreRequest {
             public PackageInfo app;
@@ -805,9 +814,18 @@
             }
         }
 
-        PerformRestoreThread(IBackupTransport transport, int restoreSetToken) {
+        PerformRestoreThread(IBackupTransport transport, IRestoreObserver observer,
+                long restoreSetToken) {
             mTransport = transport;
+            mObserver = observer;
             mToken = restoreSetToken;
+
+            try {
+                mStateDir = new File(mBaseStateDir, transport.transportDirName());
+            } catch (RemoteException e) {
+                // can't happen; the transport is local
+            }
+            mStateDir.mkdirs();
         }
 
         @Override
@@ -816,130 +834,175 @@
             /**
              * Restore sequence:
              *
-             * 1. start up the transport session
-             * 2. get the restore set description for our identity
-             * 3. for each app in the restore set:
+             * 1. get the restore set description for our identity
+             * 2. for each app in the restore set:
              *    3.a. if it's restorable on this device, add it to the restore queue
-             * 4. for each app in the restore queue:
-             *    4.a. clear the app data
-             *    4.b. get the restore data for the app from the transport
-             *    4.c. launch the backup agent for the app
-             *    4.d. agent.doRestore() with the data from the server
-             *    4.e. unbind the agent [and kill the app?]
-             * 5. shut down the transport
+             * 3. for each app in the restore queue:
+             *    3.a. clear the app data
+             *    3.b. get the restore data for the app from the transport
+             *    3.c. launch the backup agent for the app
+             *    3.d. agent.doRestore() with the data from the server
+             *    3.e. unbind the agent [and kill the app?]
+             * 4. shut down the transport
              */
 
-            int err = -1;
+            int error = -1; // assume error
+
+            // build the set of apps to restore
             try {
-                err = mTransport.startSession();
-            } catch (Exception e) {
-                Log.e(TAG, "Error starting transport for restore");
-                e.printStackTrace();
-            }
+                RestoreSet[] images = mTransport.getAvailableRestoreSets();
+                if (images == null) {
+                    // STOPSHIP TODO: Handle the failure somehow?
+                    Log.e(TAG, "Error getting restore sets");
+                    return;
+                }
 
-            if (err == 0) {
-                // build the set of apps to restore
-                try {
-                    RestoreSet[] images = mTransport.getAvailableRestoreSets();
-                    if (images.length > 0) {
-                        // !!! TODO: pick out the set for this token
-                        mImage = images[0];
+                if (images.length == 0) {
+                    Log.i(TAG, "No restore sets available");
+                    return;
+                }
 
-                        // Pull the Package Manager metadata from the restore set first
-                        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
-                                mPackageManager, allAgentApps());
-                        PackageInfo pmApp = new PackageInfo();
-                        pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
-                        // !!! TODO: version currently ignored when 'restoring' the PM metadata
-                        processOneRestore(pmApp, 0,
-                                IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+                mImage = images[0];
 
-                        // build the set of apps we will attempt to restore
-                        PackageInfo[] packages = mTransport.getAppSet(mImage.token);
-                        HashSet<RestoreRequest> appsToRestore = new HashSet<RestoreRequest>();
-                        for (PackageInfo pkg: packages) {
-                            // get the real PackageManager idea of the package
-                            PackageInfo app = isRestorable(pkg);
-                            if (app != null) {
-                                // Validate against the backed-up signature block, too
-                                Metadata info = pmAgent.getRestoredMetadata(app.packageName);
-                                if (info != null) {
-                                    if (app.versionCode >= info.versionCode) {
-                                        if (DEBUG) Log.v(TAG, "Restore version "
-                                                + info.versionCode
-                                                + " compatible with app version "
-                                                + app.versionCode);
-                                        if (signaturesMatch(info.signatures, app.signatures)) {
-                                            appsToRestore.add(
-                                                    new RestoreRequest(app, info.versionCode));
-                                        } else {
-                                            Log.w(TAG, "Sig mismatch restoring "
-                                                    + app.packageName);
-                                        }
-                                    } else {
-                                        Log.i(TAG, "Restore set for " + app.packageName
-                                                + " is too new [" + info.versionCode
-                                                + "] for installed app version "
-                                                + app.versionCode);
-                                    }
-                                } else {
-                                    Log.d(TAG, "Unable to get metadata for "
-                                            + app.packageName);
-                                }
-                            }
+                // Get the list of all packages which have backup enabled.
+                // (Include the Package Manager metadata pseudo-package first.)
+                ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
+                PackageInfo omPackage = new PackageInfo();
+                omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
+                restorePackages.add(omPackage);
+
+                List<PackageInfo> agentPackages = allAgentPackages();
+                restorePackages.addAll(agentPackages);
+
+                // let the observer know that we're running
+                if (mObserver != null) {
+                    try {
+                        // !!! TODO: get an actual count from the transport after
+                        // its startRestore() runs?
+                        mObserver.restoreStarting(restorePackages.size());
+                    } catch (RemoteException e) {
+                        Log.d(TAG, "Restore observer died at restoreStarting");
+                        mObserver = null;
+                    }
+                }
+
+                if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
+                    // STOPSHIP TODO: Handle the failure somehow?
+                    Log.e(TAG, "Error starting restore operation");
+                    return;
+                }
+
+                String packageName = mTransport.nextRestorePackage();
+                if (packageName == null) {
+                    // STOPSHIP TODO: Handle the failure somehow?
+                    Log.e(TAG, "Error getting first restore package");
+                    return;
+                } else if (packageName.equals("")) {
+                    Log.i(TAG, "No restore data available");
+                    return;
+                } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+                    Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+                          + "\", found only \"" + packageName + "\"");
+                    return;
+                }
+
+                // Pull the Package Manager metadata from the restore set first
+                PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+                        mPackageManager, agentPackages);
+                processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
+                int count = 0;
+                for (;;) {
+                    packageName = mTransport.nextRestorePackage();
+                    if (packageName == null) {
+                        // STOPSHIP TODO: Handle the failure somehow?
+                        Log.e(TAG, "Error getting next restore package");
+                        return;
+                    } else if (packageName.equals("")) {
+                        break;
+                    }
+
+                    if (mObserver != null) {
+                        ++count;
+                        try {
+                            mObserver.onUpdate(count);
+                        } catch (RemoteException e) {
+                            Log.d(TAG, "Restore observer died in onUpdate");
+                            mObserver = null;
                         }
-
-                        // now run the restore queue
-                        doQueuedRestores(appsToRestore);
                     }
-                } catch (RemoteException e) {
-                    // can't happen; transports run locally
-                }
 
-                // done; shut down the transport
-                try {
-                    mTransport.endSession();
-                } catch (Exception e) {
-                    Log.e(TAG, "Error ending transport for restore");
-                    e.printStackTrace();
-                }
-            }
+                    Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
+                    if (metaInfo == null) {
+                        Log.e(TAG, "Missing metadata for " + packageName);
+                        continue;
+                    }
 
-            // even if the initial session startup failed, report that we're done here
-        }
+                    int flags = PackageManager.GET_SIGNATURES;
+                    PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+                    if (metaInfo.versionCode > packageInfo.versionCode) {
+                        Log.w(TAG, "Package " + packageName
+                                + " restore version [" + metaInfo.versionCode
+                                + "] is too new for installed version ["
+                                + packageInfo.versionCode + "]");
+                        continue;
+                    }
 
-        // restore each app in the queue
-        void doQueuedRestores(HashSet<RestoreRequest> appsToRestore) {
-            for (RestoreRequest req : appsToRestore) {
-                PackageInfo app = req.app;
-                Log.d(TAG, "starting agent for restore of " + app);
+                    if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
+                        Log.w(TAG, "Signature mismatch restoring " + packageName);
+                        continue;
+                    }
 
-                try {
-                    // Remove the app's data first
-                    clearApplicationDataSynchronous(app.packageName);
+                    if (DEBUG) Log.v(TAG, "Package " + packageName
+                            + " restore version [" + metaInfo.versionCode
+                            + "] is compatible with installed version ["
+                            + packageInfo.versionCode + "]");
 
-                    // Now perform the restore into the clean app
-                    IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo,
+                    // Now perform the actual restore
+                    clearApplicationDataSynchronous(packageName);
+                    IBackupAgent agent = bindToAgentSynchronous(
+                            packageInfo.applicationInfo,
                             IApplicationThread.BACKUP_MODE_RESTORE);
-                    if (agent != null) {
-                        processOneRestore(app, req.storedAppVersion, agent);
+                    if (agent == null) {
+                        Log.w(TAG, "Can't find backup agent for " + packageName);
+                        continue;
                     }
 
-                    // unbind even on timeout, just in case
-                    mActivityManager.unbindBackupAgent(app.applicationInfo);
-                } catch (SecurityException ex) {
-                    // Try for the next one.
-                    Log.d(TAG, "error in bind", ex);
-                } catch (RemoteException e) {
-                    // can't happen
+                    try {
+                        processOneRestore(packageInfo, metaInfo.versionCode, agent);
+                    } finally {
+                        // unbind even on timeout or failure, just in case
+                        mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
+                    }
                 }
 
+                // if we get this far, report success to the observer
+                error = 0;
+            } catch (NameNotFoundException e) {
+                // STOPSHIP TODO: Handle the failure somehow?
+                Log.e(TAG, "Invalid paackage restoring data", e);
+            } catch (RemoteException e) {
+                // STOPSHIP TODO: Handle the failure somehow?
+                Log.e(TAG, "Error restoring data", e);
+            } finally {
+                try {
+                    mTransport.finishRestore();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error finishing restore", e);
+                }
+
+                if (mObserver != null) {
+                    try {
+                        mObserver.restoreFinished(error);
+                    } catch (RemoteException e) {
+                        Log.d(TAG, "Restore observer died at restoreFinished");
+                    }
+                }
             }
         }
 
-        // Do the guts of a restore of one application, derived from the 'mImage'
-        // restore set via the 'mTransport' transport.
-        void processOneRestore(PackageInfo app, int storedAppVersion, IBackupAgent agent) {
+        // Do the guts of a restore of one application, using mTransport.getRestoreData().
+        void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent) {
             // !!! TODO: actually run the restore through mTransport
             final String packageName = app.packageName;
 
@@ -954,11 +1017,12 @@
 
                 // Run the transport's restore pass
                 // Run the target's backup pass
-                int err = -1;
                 try {
-                    err = mTransport.getRestoreData(mImage.token, app, backupData);
-                } catch (RemoteException e) {
-                    // can't happen
+                    if (!mTransport.getRestoreData(backupData)) {
+                        // STOPSHIP TODO: Handle this error somehow?
+                        Log.e(TAG, "Error getting restore data for " + packageName);
+                        return;
+                    }
                 } finally {
                     backupData.close();
                 }
@@ -973,30 +1037,18 @@
                 backupData = ParcelFileDescriptor.open(backupDataName,
                             ParcelFileDescriptor.MODE_READ_ONLY);
 
-                boolean success = false;
                 try {
-                    agent.doRestore(backupData, storedAppVersion, newState);
-                    success = true;
-                } catch (Exception e) {
-                    Log.e(TAG, "Restore failed for " + packageName);
-                    e.printStackTrace();
+                    agent.doRestore(backupData, appVersionCode, newState);
                 } finally {
                     newState.close();
                     backupData.close();
                 }
 
                 // if everything went okay, remember the recorded state now
-                if (success) {
-                    File savedStateName = new File(mStateDir, packageName);
-                    newStateName.renameTo(savedStateName);
-                }
-            } catch (FileNotFoundException fnfe) {
-                Log.v(TAG, "Couldn't open file for restore: " + fnfe);
-            } catch (IOException ioe) {
-                Log.e(TAG, "Unable to process restore file: " + ioe);
+                File savedStateName = new File(mStateDir, packageName);
+                newStateName.renameTo(savedStateName);
             } catch (Exception e) {
-                Log.e(TAG, "Final exception guard in restore:");
-                e.printStackTrace();
+                Log.e(TAG, "Error restoring data for " + packageName, e);
             }
         }
     }
@@ -1049,7 +1101,7 @@
 
                 if (DEBUG) {
                     int numKeys = mPendingBackups.size();
-                    Log.d(TAG, "Scheduling backup for " + numKeys + " participants:");
+                    Log.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
                     for (BackupRequest b : mPendingBackups.values()) {
                         Log.d(TAG, "    + " + b + " agent=" + b.appInfo.backupAgentName);
                     }
@@ -1079,7 +1131,7 @@
     // Run a backup pass immediately for any applications that have declared
     // that they have pending updates.
     public void backupNow() throws RemoteException {
-        mContext.enforceCallingPermission("android.permission.BACKUP", "tryBackupNow");
+        mContext.enforceCallingPermission("android.permission.BACKUP", "backupNow");
 
         if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
         synchronized (mQueueLock) {
@@ -1087,21 +1139,78 @@
         }
     }
 
-    // Report the currently active transport
-    public int getCurrentTransport() {
-        mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
-        Log.v(TAG, "getCurrentTransport() returning " + mTransportId);
-        return mTransportId;
+    // Enable/disable the backup transport
+    public void setBackupEnabled(boolean enable) {
+        mContext.enforceCallingPermission("android.permission.BACKUP", "setBackupEnabled");
+
+        boolean wasEnabled = mEnabled;
+        synchronized (this) {
+            SystemProperties.set(BACKUP_ENABLED_PROPERTY, enable ? "true" : "false");
+            mEnabled = enable;
+        }
+
+        if (enable && !wasEnabled) {
+            synchronized (mQueueLock) {
+                if (mPendingBackups.size() > 0) {
+                    // !!! TODO: better policy around timing of the first backup pass
+                    if (DEBUG) Log.v(TAG, "Backup enabled with pending data changes, scheduling");
+                    this.scheduleBackupPassLocked(COLLECTION_INTERVAL);
+                }
+            }
+        }
+}
+
+    // Report whether the backup mechanism is currently enabled
+    public boolean isBackupEnabled() {
+        mContext.enforceCallingPermission("android.permission.BACKUP", "isBackupEnabled");
+        return mEnabled;    // no need to synchronize just to read it
     }
 
-    // Select which transport to use for the next backup operation
-    public int selectBackupTransport(int transportId) {
+    // Report the name of the currently active transport
+    public String getCurrentTransport() {
+        mContext.enforceCallingPermission("android.permission.BACKUP", "getCurrentTransport");
+        Log.v(TAG, "getCurrentTransport() returning " + mCurrentTransport);
+        return mCurrentTransport;
+    }
+
+    // Report all known, available backup transports
+    public String[] listAllTransports() {
+        mContext.enforceCallingPermission("android.permission.BACKUP", "listAllTransports");
+
+        String[] list = null;
+        ArrayList<String> known = new ArrayList<String>();
+        for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
+            if (entry.getValue() != null) {
+                known.add(entry.getKey());
+            }
+        }
+
+        if (known.size() > 0) {
+            list = new String[known.size()];
+            known.toArray(list);
+        }
+        return list;
+    }
+
+    // Select which transport to use for the next backup operation.  If the given
+    // name is not one of the available transports, no action is taken and the method
+    // returns null.
+    public String selectBackupTransport(String transport) {
         mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
 
-        int prevTransport = mTransportId;
-        mTransportId = transportId;
-        Log.v(TAG, "selectBackupTransport() set " + mTransportId + " returning " + prevTransport);
-        return prevTransport;
+        synchronized (mTransports) {
+            String prevTransport = null;
+            if (mTransports.get(transport) != null) {
+                prevTransport = mCurrentTransport;
+                mCurrentTransport = transport;
+                SystemProperties.set(BACKUP_TRANSPORT_PROPERTY, transport);
+                Log.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+                        + " returning " + prevTransport);
+            } else {
+                Log.w(TAG, "Attempt to select unavailable transport " + transport);
+            }
+            return prevTransport;
+        }
     }
 
     // Callback: a requested backup agent has been instantiated.  This should only
@@ -1139,7 +1248,7 @@
     }
 
     // Hand off a restore session
-    public IRestoreSession beginRestoreSession(int transportID) {
+    public IRestoreSession beginRestoreSession(String transport) {
         mContext.enforceCallingPermission("android.permission.BACKUP", "beginRestoreSession");
 
         synchronized(this) {
@@ -1147,7 +1256,7 @@
                 Log.d(TAG, "Restore session requested but one already active");
                 return null;
             }
-            mActiveRestoreSession = new RestoreSession(transportID);
+            mActiveRestoreSession = new RestoreSession(transport);
         }
         return mActiveRestoreSession;
     }
@@ -1160,8 +1269,8 @@
         private IBackupTransport mRestoreTransport = null;
         RestoreSet[] mRestoreSets = null;
 
-        RestoreSession(int transportID) {
-            mRestoreTransport = getTransport(transportID);
+        RestoreSession(String transport) {
+            mRestoreTransport = getTransport(transport);
         }
 
         // --- Binder interface ---
@@ -1183,15 +1292,15 @@
             }
         }
 
-        public int performRestore(int token) throws android.os.RemoteException {
+        public int performRestore(long token, IRestoreObserver observer)
+                throws android.os.RemoteException {
             mContext.enforceCallingPermission("android.permission.BACKUP", "performRestore");
 
             if (mRestoreSets != null) {
                 for (int i = 0; i < mRestoreSets.length; i++) {
                     if (token == mRestoreSets[i].token) {
-                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE,
-                                mRestoreTransport);
-                        msg.arg1 = token;
+                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+                        msg.obj = new RestoreParams(mRestoreTransport, observer, token);
                         mBackupHandler.sendMessage(msg);
                         return 0;
                     }
@@ -1206,7 +1315,7 @@
             mContext.enforceCallingPermission("android.permission.BACKUP",
                     "endRestoreSession");
 
-            mRestoreTransport.endSession();
+            mRestoreTransport.finishRestore();
             mRestoreTransport = null;
             synchronized(BackupManagerService.this) {
                 if (BackupManagerService.this.mActiveRestoreSession == this) {
@@ -1222,6 +1331,11 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (mQueueLock) {
+            pw.println("Available transports:");
+            for (String t : listAllTransports()) {
+                String pad = (t.equals(mCurrentTransport)) ? "  * " : "    ";
+                pw.println(pad + t);
+            }
             int N = mBackupParticipants.size();
             pw.println("Participants:");
             for (int i=0; i<N; i++) {
@@ -1230,14 +1344,12 @@
                 pw.println(uid);
                 HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
                 for (ApplicationInfo app: participants) {
-                    pw.print("    ");
-                    pw.println(app.toString());
+                    pw.println("    " + app.toString());
                 }
             }
             pw.println("Pending: " + mPendingBackups.size());
             for (BackupRequest req : mPendingBackups.values()) {
-                pw.print("   ");
-                pw.println(req);
+                pw.println("    " + req);
             }
         }
     }
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index d620eb1..66fb86d 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -57,7 +57,7 @@
     // is stored using the package name as a key)
     private static final String GLOBAL_METADATA_KEY = "@meta@";
 
-    private List<ApplicationInfo> mAllApps;
+    private List<PackageInfo> mAllPackages;
     private PackageManager mPackageManager;
     private HashMap<String, Metadata> mRestoredSignatures;
 
@@ -73,9 +73,9 @@
 
     // We're constructed with the set of applications that are participating
     // in backup.  This set changes as apps are installed & removed.
-    PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) {
+    PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
         mPackageManager = packageMgr;
-        mAllApps = apps;
+        mAllPackages = packages;
         mRestoredSignatures = null;
     }
 
@@ -118,8 +118,8 @@
 
             // For each app we have on device, see if we've backed it up yet.  If not,
             // write its signature block to the output, keyed on the package name.
-            for (ApplicationInfo app : mAllApps) {
-                String packName = app.packageName;
+            for (PackageInfo pkg : mAllPackages) {
+                String packName = pkg.packageName;
                 if (!existing.contains(packName)) {
                     // We haven't stored this app's signatures yet, so we do that now
                     try {
@@ -186,7 +186,7 @@
         }
 
         // Finally, write the new state blob -- just the list of all apps we handled
-        writeStateFile(mAllApps, newState);
+        writeStateFile(mAllPackages, newState);
     }
 
     // "Restore" here is a misnomer.  What we're really doing is reading back the
@@ -327,7 +327,7 @@
     }
 
     // Util: write out our new backup state file
-    private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
+    private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
         FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
         DataOutputStream out = new DataOutputStream(outstream);
 
@@ -338,8 +338,8 @@
             out.write(metaNameBuf);
 
             // now write all the app names too
-            for (ApplicationInfo app : apps) {
-                byte[] pkgNameBuf = app.packageName.getBytes();
+            for (PackageInfo pkg : pkgs) {
+                byte[] pkgNameBuf = pkg.packageName.getBytes();
                 out.writeInt(pkgNameBuf.length);
                 out.write(pkgNameBuf);
             }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 048669a..972aa98 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -968,35 +968,7 @@
 
             if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLP(a.info, flags)) {
-                ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
-                if (ainfo != null) {
-                    ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
-                            PackageManager.GET_SUPPORTS_DENSITIES);
-                    if (appInfo != null &&
-                            (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) == 0) {
-                        // Check if the screen size is same as what the application expect.
-                        CompatibilityInfo info = new CompatibilityInfo(appInfo);
-                        DisplayMetrics metrics = new DisplayMetrics();
-                        metrics.setTo(mMetrics);
-                        int orientation = mMetrics.widthPixels > mMetrics.heightPixels ?
-                                Configuration.ORIENTATION_LANDSCAPE :
-                                Configuration.ORIENTATION_PORTRAIT;
-                        metrics.updateMetrics(info, orientation);
-                        if (!info.mExpandable) {
-                            // Don't allow an app that cannot expand to handle rotation.
-                            ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
-                        } else {
-                            appInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
-                        }
-                        if (DEBUG_SETTINGS) {
-                            Log.d(TAG, "component=" + component +
-                                    ", expandable:" +
-                                    ((appInfo.flags &
-                                            ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0));
-                        }
-                    }
-                }
-                return ainfo;
+                return PackageParser.generateActivityInfo(a, flags);
             }
             if (mResolveComponentName.equals(component)) {
                 return mResolveActivity;
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index b601ece..9f2856c 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -462,6 +462,15 @@
     //
 
     private void broadcastServiceStateChanged(ServiceState state) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.noteAirplaneMode(state.getState() == ServiceState.STATE_POWER_OFF);
+        } catch (RemoteException re) {
+            // Can't do much
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java
index 5532894..d921baf 100644
--- a/services/java/com/android/server/WallpaperService.java
+++ b/services/java/com/android/server/WallpaperService.java
@@ -18,8 +18,10 @@
 
 import static android.os.FileObserver.*;
 import static android.os.ParcelFileDescriptor.*;
+
 import android.app.IWallpaperService;
 import android.app.IWallpaperServiceCallback;
+import android.backup.BackupManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -154,7 +156,16 @@
     public ParcelFileDescriptor setWallpaper() {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
         try {
-            return ParcelFileDescriptor.open(WALLPAPER_FILE, MODE_CREATE|MODE_READ_WRITE);
+            ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+                    MODE_CREATE|MODE_READ_WRITE);
+
+            // changing the wallpaper means we'll need to back up the new one
+            long origId = Binder.clearCallingIdentity();
+            BackupManager bm = new BackupManager(mContext);
+            bm.dataChanged();
+            Binder.restoreCallingIdentity(origId);
+
+            return fd;
         } catch (FileNotFoundException e) {
             if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e);
         }
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index fef3598..68bf4fb 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -504,6 +504,7 @@
                 if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
                         mPhonePss)) {
                     // Just kill the phone process and let it restart.
+                    Log.i(TAG, "Watchdog is killing the phone process");
                     Process.killProcess(mPhonePid);
                 }
             } else {
@@ -848,6 +849,7 @@
 
             // Only kill the process if the debugger is not attached.
             if (!Debug.isDebuggerConnected()) {
+                Log.i(TAG, "Watchdog is killing the system process");
                 Process.killProcess(Process.myPid());
             }
         }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3b47ae7..9bad153 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -77,6 +77,7 @@
 import android.os.SystemProperties;
 import android.os.TokenWatcher;
 import android.provider.Settings;
+import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseIntArray;
@@ -415,7 +416,8 @@
     final Rect mTempRect = new Rect();
 
     final Configuration mTempConfiguration = new Configuration();
-
+    int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
+    
     public static WindowManagerService main(Context context,
             PowerManagerService pm, boolean haveInputMethods) {
         WMThread thr = new WMThread(context, pm, haveInputMethods);
@@ -3724,6 +3726,40 @@
             orientation = Configuration.ORIENTATION_LANDSCAPE;
         }
         config.orientation = orientation;
+        
+        if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
+            // Note we only do this once because at this point we don't
+            // expect the screen to change in this way at runtime, and want
+            // to avoid all of this computation for every config change.
+            DisplayMetrics dm = new DisplayMetrics();
+            mDisplay.getMetrics(dm);
+            int longSize = dw;
+            int shortSize = dh;
+            if (longSize < shortSize) {
+                int tmp = longSize;
+                longSize = shortSize;
+                shortSize = tmp;
+            }
+            longSize = (int)(longSize/dm.density);
+            shortSize = (int)(shortSize/dm.density);
+            
+            // These semi-magic numbers define our compatibility modes for
+            // applications with different screens.  Don't change unless you
+            // make sure to test lots and lots of apps!
+            if (longSize < 470) {
+                // This is shorter than an HVGA normal density screen (which
+                // is 480 pixels on its long side).
+                screenLayout = Configuration.SCREENLAYOUT_SMALL;
+            } else if (longSize > 490 && shortSize > 330) {
+                // This is larger than an HVGA normal density screen (which
+                // is 480x320 pixels).
+                screenLayout = Configuration.SCREENLAYOUT_LARGE;
+            } else {
+                screenLayout = Configuration.SCREENLAYOUT_NORMAL;
+            }
+        }
+        config.screenLayout = screenLayout;
+        
         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
         config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
         mPolicy.adjustConfigurationLw(config);
@@ -3798,7 +3834,7 @@
                 "dispatchPointer " + ev);
 
         Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, true, false);
+                ev, true, false, pid, uid);
 
         int action = ev.getAction();
 
@@ -3996,7 +4032,7 @@
                 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
 
         Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, false, false);
+                ev, false, false, pid, uid);
         if (focusObj == null) {
             Log.w(TAG, "No focus window, dropping trackball: " + ev);
             if (qev != null) {
@@ -4067,7 +4103,7 @@
         if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
 
         Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
-                null, false, false);
+                null, false, false, pid, uid);
         if (focusObj == null) {
             Log.w(TAG, "No focus window, dropping: " + event);
             return INJECT_FAILED;
@@ -4184,10 +4220,14 @@
         KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
                 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
 
-        int result = dispatchKey(newEvent, Binder.getCallingPid(), Binder.getCallingUid());
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final long ident = Binder.clearCallingIdentity();
+        final int result = dispatchKey(newEvent, pid, uid);
         if (sync) {
-            mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
+            mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
         }
+        Binder.restoreCallingIdentity(ident);
         switch (result) {
             case INJECT_NO_PERMISSION:
                 throw new SecurityException(
@@ -4208,10 +4248,14 @@
      * @return Returns true if event was dispatched, false if it was dropped for any reason
      */
     public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
-        int result = dispatchPointer(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final long ident = Binder.clearCallingIdentity();
+        final int result = dispatchPointer(null, ev, pid, uid);
         if (sync) {
-            mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
+            mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
         }
+        Binder.restoreCallingIdentity(ident);
         switch (result) {
             case INJECT_NO_PERMISSION:
                 throw new SecurityException(
@@ -4232,10 +4276,14 @@
      * @return Returns true if event was dispatched, false if it was dropped for any reason
      */
     public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
-        int result = dispatchTrackball(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final long ident = Binder.clearCallingIdentity();
+        final int result = dispatchTrackball(null, ev, pid, uid);
         if (sync) {
-            mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
+            mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
         }
+        Binder.restoreCallingIdentity(ident);
         switch (result) {
             case INJECT_NO_PERMISSION:
                 throw new SecurityException(
@@ -4344,7 +4392,7 @@
          */
         Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
                 MotionEvent nextMotion, boolean isPointerEvent,
-                boolean failIfTimeout) {
+                boolean failIfTimeout, int callingPid, int callingUid) {
             long startTime = SystemClock.uptimeMillis();
             long keyDispatchingTimeout = 5 * 1000;
             long waitedFor = 0;
@@ -4362,7 +4410,7 @@
                         ", mLastWin=" + mLastWin);
                 if (targetIsNew) {
                     Object target = findTargetWindow(nextKey, qev, nextMotion,
-                            isPointerEvent);
+                            isPointerEvent, callingPid, callingUid);
                     if (target == SKIP_TARGET_TOKEN) {
                         // The user has pressed a special key, and we are
                         // dropping all pending events before it.
@@ -4538,7 +4586,8 @@
         }
 
         Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent) {
+                MotionEvent nextMotion, boolean isPointerEvent,
+                int callingPid, int callingUid) {
             mOutsideTouchTargets = null;
 
             if (nextKey != null) {
@@ -4547,9 +4596,16 @@
                 final int repeatCount = nextKey.getRepeatCount();
                 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
                 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
+                
                 if (!dispatch) {
-                    mPolicy.interceptKeyTi(null, keycode,
-                            nextKey.getMetaState(), down, repeatCount);
+                    if (callingUid == 0 ||
+                            mContext.checkPermission(
+                                    android.Manifest.permission.INJECT_EVENTS,
+                                    callingPid, callingUid)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                        mPolicy.interceptKeyTi(null, keycode,
+                                nextKey.getMetaState(), down, repeatCount);
+                    }
                     Log.w(TAG, "Event timeout during app switch: dropping "
                             + nextKey);
                     return SKIP_TARGET_TOKEN;
@@ -4564,9 +4620,16 @@
 
                 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
 
-                if (mPolicy.interceptKeyTi(focus,
-                        keycode, nextKey.getMetaState(), down, repeatCount)) {
-                    return CONSUMED_EVENT_TOKEN;
+                if (callingUid == 0 ||
+                        (focus != null && callingUid == focus.mSession.mUid) ||
+                        mContext.checkPermission(
+                                android.Manifest.permission.INJECT_EVENTS,
+                                callingPid, callingUid)
+                                == PackageManager.PERMISSION_GRANTED) {
+                    if (mPolicy.interceptKeyTi(focus,
+                            keycode, nextKey.getMetaState(), down, repeatCount)) {
+                        return CONSUMED_EVENT_TOKEN;
+                    }
                 }
 
                 return focus;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 16bb29d..6d04b6b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -61,6 +61,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -1517,7 +1518,8 @@
                 }
             }
             
-            synchronized(mBatteryStatsService.getActiveStatistics()) {
+            final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
+            synchronized(bstats) {
                 synchronized(mPidsSelfLocked) {
                     if (haveNewCpuStats) {
                         if (mBatteryStatsService.isOnBattery()) {
@@ -1529,12 +1531,18 @@
                                 if (pr != null) {
                                     BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
                                     ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+                                } else {
+                                    BatteryStatsImpl.Uid.Proc ps =
+                                            bstats.getProcessStatsLocked(st.name, st.pid);
+                                    if (ps != null) {
+                                        ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+                                    }
                                 }
                             }
                         }
                     }
                 }
-        
+
                 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
                     mLastWriteTime = now;
                     mBatteryStatsService.getActiveStatistics().writeLocked();
@@ -10464,8 +10472,17 @@
     // done with this agent
     public void unbindBackupAgent(ApplicationInfo appInfo) {
         if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
+        if (appInfo == null) {
+            Log.w(TAG, "unbind backup agent for null app");
+            return;
+        }
 
         synchronized(this) {
+            if (mBackupAppName == null) {
+                Log.w(TAG, "Unbinding backup agent with no active backup");
+                return;
+            }
+
             if (!mBackupAppName.equals(appInfo.packageName)) {
                 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
                 return;
@@ -12592,51 +12609,63 @@
     }
 
     public boolean profileControl(String process, boolean start,
-            String path) throws RemoteException {
+            String path, ParcelFileDescriptor fd) throws RemoteException {
 
-        synchronized (this) {
-            // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
-            // its own permission.
-            if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
-                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires permission "
-                        + android.Manifest.permission.SET_ACTIVITY_WATCHER);
-            }
-            
-            ProcessRecord proc = null;
-            try {
-                int pid = Integer.parseInt(process);
-                synchronized (mPidsSelfLocked) {
-                    proc = mPidsSelfLocked.get(pid);
+        try {
+            synchronized (this) {
+                // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+                // its own permission.
+                if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Requires permission "
+                            + android.Manifest.permission.SET_ACTIVITY_WATCHER);
                 }
-            } catch (NumberFormatException e) {
-            }
-            
-            if (proc == null) {
-                HashMap<String, SparseArray<ProcessRecord>> all
-                        = mProcessNames.getMap();
-                SparseArray<ProcessRecord> procs = all.get(process);
-                if (procs != null && procs.size() > 0) {
-                    proc = procs.valueAt(0);
+                
+                if (start && fd == null) {
+                    throw new IllegalArgumentException("null fd");
                 }
-            }
-            
-            if (proc == null || proc.thread == null) {
-                throw new IllegalArgumentException("Unknown process: " + process);
-            }
-            
-            boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
-            if (isSecure) {
-                if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                    throw new SecurityException("Process not debuggable: " + proc);
+                
+                ProcessRecord proc = null;
+                try {
+                    int pid = Integer.parseInt(process);
+                    synchronized (mPidsSelfLocked) {
+                        proc = mPidsSelfLocked.get(pid);
+                    }
+                } catch (NumberFormatException e) {
                 }
-            }
+                
+                if (proc == null) {
+                    HashMap<String, SparseArray<ProcessRecord>> all
+                            = mProcessNames.getMap();
+                    SparseArray<ProcessRecord> procs = all.get(process);
+                    if (procs != null && procs.size() > 0) {
+                        proc = procs.valueAt(0);
+                    }
+                }
+                
+                if (proc == null || proc.thread == null) {
+                    throw new IllegalArgumentException("Unknown process: " + process);
+                }
+                
+                boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
+                if (isSecure) {
+                    if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+                        throw new SecurityException("Process not debuggable: " + proc);
+                    }
+                }
             
-            try {
-                proc.thread.profilerControl(start, path);
+                proc.thread.profilerControl(start, path, fd);
+                fd = null;
                 return true;
-            } catch (RemoteException e) {
-                throw new IllegalStateException("Process disappeared");
+            }
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Process disappeared");
+        } finally {
+            if (fd != null) {
+                try {
+                    fd.close();
+                } catch (IOException e) {
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 9a4b642..39a1ee0 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -16,9 +16,6 @@
 
 package com.android.server.am;
 
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BatteryStatsImpl;
-
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
@@ -26,8 +23,12 @@
 import android.os.Process;
 import android.os.ServiceManager;
 import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -191,7 +192,14 @@
             mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
         }
     }
-    
+
+    public void noteAirplaneMode(boolean airplaneMode) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteAirplaneModeLocked(airplaneMode);
+        }
+    }
+
     public void noteWifiOn(int uid) {
         enforceCallingPermission();
         synchronized (mStats) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a79eb3a..bf5df88 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -612,6 +612,21 @@
     }
 
     /**
+     * Returns the voice mail count.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @hide
+     */
+    public int getVoiceMessageCount() {
+        try {
+            return getITelephony().getVoiceMessageCount();
+        } catch (RemoteException ex) {
+        }
+        return 0;
+    }
+
+    /**
      * Retrieves the alphabetic identifier associated with the voice
      * mail number.
      * <p>
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index af79404..c074cb8 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -98,8 +98,8 @@
     //***** Constants
     protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000;
 
-    /** Cap out with 1 hour retry interval. */
-    protected static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000;
+    /** Cap out with 30 min retry interval. */
+    protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000;
 
     /** Slow poll when attempting connection recovery. */
     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 6e6f64c..d83b135 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -241,7 +241,7 @@
     /**
       * Returns the unread count of voicemails
       */
-    int getCountVoiceMessages();
+    int getVoiceMessageCount();
 
 }
 
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index 114094b..ea24c25 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -196,7 +196,7 @@
      * If not available (eg, on an older CPHS SIM) -1 is returned if
      * getVoiceMessageWaiting() is true
      */
-    public int getCountVoiceMessages() {
+    public int getVoiceMessageCount() {
         return countVoiceMessages;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index cdbfd61..c8d384d 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -831,7 +831,7 @@
      * Returns unread voicemail count. This count is shown when the  voicemail
      * notification is expanded.<p>
      */
-    int getCountVoiceMessages();
+    int getVoiceMessageCount();
 
     /**
      * Returns the alpha tag associated with the voice mail number.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 0783fe0..a26e729 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -631,6 +631,11 @@
         mNotifier.notifyDataActivity(this);
     }
 
+    public void notifyMessageWaitingIndicator() {
+        // This function is added to send the notification to DefaultPhoneNotifier.
+        mNotifier.notifyMessageWaitingChanged(this);
+    }
+
     public void notifyDataConnection(String reason) {
         mNotifier.notifyDataConnection(this, reason);
     }
@@ -638,7 +643,7 @@
     public abstract String getPhoneName();
 
     /** @hide */
-    public int getCountVoiceMessages(){
+    public int getVoiceMessageCount(){
         return 0;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 4bb24dc..5b3c8dd 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -435,8 +435,8 @@
     }
 
      /** @hide */
-    public int getCountVoiceMessages(){
-        return mActivePhone.getCountVoiceMessages();
+    public int getVoiceMessageCount(){
+        return mActivePhone.getVoiceMessageCount();
     }
 
     public String getVoiceMailAlphaTag() {
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 9f780c9..4db3e5b 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1365,7 +1365,6 @@
         RILRequest rr
                 = RILRequest.obtain(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result);
 
-        rr.mp.writeInt(2);
         rr.mp.writeInt(success ? 0 : 1); //RIL_CDMA_SMS_ErrorClass
         // cause code according to X.S004-550E
         rr.mp.writeInt(cause);
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index a3016fa..890ea63 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -78,6 +78,7 @@
     protected static final String[] RAW_PROJECTION = new String[] {
         "pdu",
         "sequence",
+        "destination_port",
     };
 
     static final int MAIL_SEND_SMS = 1;
@@ -289,7 +290,13 @@
             sms = (SmsMessage) ar.result;
             try {
                 if (mStorageAvailable) {
-                    dispatchMessage(sms.mWrappedSmsMessage);
+                    int result = dispatchMessage(sms.mWrappedSmsMessage);
+                    if (result != Activity.RESULT_OK) {
+                        // RESULT_OK means that message was broadcast for app(s) to handle.
+                        // Any other result, we should ack here.
+                        boolean handled = (result == Intents.RESULT_SMS_HANDLED);
+                        acknowledgeLastIncomingSms(handled, result, null);
+                    }
                 } else {
                     acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_OUT_OF_MEMORY, null);
                 }
@@ -469,8 +476,11 @@
      * Dispatches an incoming SMS messages.
      *
      * @param sms the incoming message from the phone
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    protected abstract void dispatchMessage(SmsMessageBase sms);
+    protected abstract int dispatchMessage(SmsMessageBase sms);
 
 
     /**
@@ -478,8 +488,11 @@
      * the part is stored for later processing.
      *
      * NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null.
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    protected void processMessagePart(SmsMessageBase sms,
+    protected int processMessagePart(SmsMessageBase sms,
             SmsHeader.ConcatRef concatRef, SmsHeader.PortAddrs portAddrs) {
 
         // Lookup all other related parts
@@ -506,8 +519,7 @@
                     values.put("destination_port", portAddrs.destPort);
                 }
                 mResolver.insert(mRawUri, values);
-                acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null);
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
 
             // All the parts are in place, deal with them
@@ -529,8 +541,7 @@
         } catch (SQLException e) {
             Log.e(TAG, "Can't access multipart SMS database", e);
             // TODO:  Would OUT_OF_MEMORY be more appropriate?
-            acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null);
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         } finally {
             if (cursor != null) cursor.close();
         }
@@ -555,7 +566,7 @@
                     output.write(data, 0, data.length);
                 }
                 // Handle the PUSH
-                mWapPush.dispatchWapPdu(output.toByteArray());
+                return mWapPush.dispatchWapPdu(output.toByteArray());
             } else {
                 // The messages were sent to a port, so concoct a URI for it
                 dispatchPortAddressedPdus(pdus, portAddrs.destPort);
@@ -564,6 +575,7 @@
             // The messages were not sent to a port
             dispatchPdus(pdus);
         }
+        return Activity.RESULT_OK;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index a9aacda..99709406 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -16,8 +16,10 @@
 
 package com.android.internal.telephony;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.util.Config;
 import android.util.Log;
@@ -51,8 +53,11 @@
      * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
      *
      * @param pdu The WAP PDU, made up of one or more SMS PDUs
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    public void dispatchWapPdu(byte[] pdu) {
+    public int dispatchWapPdu(byte[] pdu) {
 
         if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
 
@@ -64,7 +69,7 @@
         if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
                 (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
             if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
-            return;
+            return Intents.RESULT_SMS_HANDLED;
         }
 
         pduDecoder = new WspTypeDecoder(pdu);
@@ -77,7 +82,7 @@
          */
         if (pduDecoder.decodeUintvarInteger(index) == false) {
             if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error.");
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         headerLength = (int)pduDecoder.getValue32();
         index += pduDecoder.getDecodedDataLength();
@@ -98,7 +103,7 @@
          */
         if (pduDecoder.decodeContentType(index) == false) {
             if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         int binaryContentType;
         String mimeType = pduDecoder.getValueString();
@@ -128,7 +133,7 @@
                         Log.w(LOG_TAG,
                                 "Received PDU. Unsupported Content-Type = " + binaryContentType);
                     }
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
         } else {
             if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) {
@@ -145,7 +150,7 @@
                 binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
             } else {
                 if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
         }
         index += pduDecoder.getDecodedDataLength();
@@ -167,6 +172,7 @@
         if (dispatchedByApplication == false) {
             dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex);
         }
+        return Activity.RESULT_OK;
     }
 
     private void dispatchWapPdu_default(
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 9aa7eab..3362de8 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManagerNative;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
@@ -26,6 +27,7 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.SystemProperties;
+import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.telephony.CellLocation;
 import android.telephony.PhoneNumberUtils;
@@ -40,6 +42,7 @@
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccException;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 import com.android.internal.telephony.IccSmsInterfaceManager;
@@ -65,6 +68,9 @@
 
     // Default Emergency Callback Mode exit timer
     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 30000;
+    static final String VM_COUNT_CDMA = "vm_count_key_cdma";
+    private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
+    private String mVmNumber = null;
 
     //***** Instance Variables
     CdmaCallTracker mCT;
@@ -147,6 +153,9 @@
         // This is needed to handle phone process crashes
         String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
         mIsPhoneInECMState = inEcm.equals("true");
+
+        // Notify voicemails.
+        notifier.notifyMessageWaitingChanged(this);
     }
 
     public void dispose() {
@@ -300,7 +309,7 @@
 
     public boolean
     getMessageWaitingIndicator() {
-        return mRuimRecords.getVoiceMessageWaiting();
+        return (getVoiceMessageCount() > 0);
     }
 
     public List<? extends MmiCode>
@@ -678,22 +687,33 @@
     public void setVoiceMailNumber(String alphaTag,
                                    String voiceMailNumber,
                                    Message onComplete) {
-        //mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete);
-        //TODO: Where do we have to store this value has to be clarified with QC
+        Message resp;
+        mVmNumber = voiceMailNumber;
+        resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
+        mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
     }
 
     public String getVoiceMailNumber() {
-        //TODO: Where can we get this value has to be clarified with QC
-        //return mSIMRecords.getVoiceMailNumber();
-//      throw new RuntimeException();
-        return "*86";
+        String number = null;
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+        // TODO(Moto): The default value of voicemail number should be read from a system property
+        number = sp.getString(VM_NUMBER_CDMA, "*86");
+        return number;
     }
 
     /* Returns Number of Voicemails
      * @hide
      */
-    public int getCountVoiceMessages() {
-        return mRuimRecords.getCountVoiceMessages();
+    public int getVoiceMessageCount() {
+        int voicemailCount =  mRuimRecords.getVoiceMessageCount();
+        // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
+        // that phone was power cycled and would have lost the voicemail count.
+        // So get the count from preferences.
+        if (voicemailCount == 0) {
+            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+            voicemailCount = sp.getInt(VM_COUNT_CDMA, 0);
+        }
+        return voicemailCount;
     }
 
     public String getVoiceMailAlphaTag() {
@@ -820,9 +840,10 @@
         mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
     }
 
-    public void
-    notifyMessageWaitingIndicator() {
-        mNotifier.notifyMessageWaitingChanged(this);
+    /* This function is overloaded to send number of voicemails instead of sending true/false */
+    /*package*/ void
+    updateMessageWaitingIndicator(int mwi) {
+        mRuimRecords.setVoiceMessageWaiting(1, mwi);
     }
 
     /**
@@ -984,6 +1005,19 @@
                 }
                 break;
 
+                case EVENT_SET_VM_NUMBER_DONE:{
+                    ar = (AsyncResult)msg.obj;
+                    if (IccException.class.isInstance(ar.exception)) {
+                        storeVoiceMailNumber(mVmNumber);
+                        ar.exception = null;
+                    }
+                    onComplete = (Message) ar.userObj;
+                    if (onComplete != null) {
+                        AsyncResult.forMessage(onComplete, ar.result, ar.exception);
+                        onComplete.sendToTarget();
+                    }
+                }
+
                 default:{
                     throw new RuntimeException("unexpected event not handled");
                 }
@@ -1198,4 +1232,16 @@
         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
         return mEriManager.getCdmaEriText(roamInd, defRoamInd);
     }
+
+    /**
+     * Store the voicemail number in preferences
+     */
+    private void storeVoiceMailNumber(String number) {
+        // Update the preference value of voicemail number
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+        SharedPreferences.Editor editor = sp.edit();
+        editor.putString(VM_NUMBER_CDMA, number);
+        editor.commit();
+    }
+
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index da9fd0c4..ed2ea90 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -253,11 +253,7 @@
             // Always unmute when answering a new call
             setMute(false);
             cm.acceptCall(obtainCompleteMessage());
-        } else if ((foregroundCall.connections.size() > 0) &&
-                   (ringingCall.getState() == CdmaCall.State.WAITING)) {
-            // TODO(Moto): jsh asks, "Is this check necessary? I don't think it should be
-            // possible to have no fg connection and a WAITING call, but if we should hit
-            // this situation, is a CallStateExcetion appropriate?"
+        } else if (ringingCall.getState() == CdmaCall.State.WAITING) {
             CdmaConnection cwConn = (CdmaConnection)(ringingCall.getLatestConnection());
 
             // Since there is no network response for supplimentary
@@ -530,10 +526,6 @@
                         CdmaConnection cn = (CdmaConnection)foregroundCall.connections.get(n);
                         droppedDuringPoll.add(cn);
                     }
-                    // TODO(Moto): jsh asks, "Are we sure we don't need to do this for
-                    // ringingCall as well? What if there's a WAITING call (ie, UI timer
-                    // hasn't expired, moving it to DISCONNECTED)? How/when will it
-                    // transition to DISCONNECTED?"
                 }
                 foregroundCall.setGeneric(false);
                 // Dropped connections are removed from the CallTracker
@@ -681,8 +673,12 @@
             // set the ringing call state to IDLE here to avoid a race condition
             // where a new call waiting could get a hang up from an old call
             // waiting ringingCall.
-            // TODO(Moto): jsh asks, "Should we call conn.ondisconnect() here or Somewhere?"
-            ringingCall.detach(conn);
+            //
+            // PhoneApp does the call log itself since only PhoneApp knows
+            // the hangup reason is user ignoring or timing out. So conn.onDisconnect()
+            // is not called here. Instead, conn.onLocalDisconnect() is called.
+            conn.onLocalDisconnect();
+            phone.notifyCallStateChanged();
             return;
         } else {
             try {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 588bdf0..025382d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -452,12 +452,7 @@
         this.cause = cause;
 
         if (!disconnected) {
-            index = -1;
-
-            disconnectTime = System.currentTimeMillis();
-            duration = SystemClock.elapsedRealtime() - connectTimeReal;
-            disconnected = true;
-
+            doDisconnect();
             if (Config.LOGD) Log.d(LOG_TAG,
                     "[CDMAConn] onDisconnect: cause=" + cause);
 
@@ -470,6 +465,21 @@
         releaseWakeLock();
     }
 
+    /** Called when the call waiting connection has been hung up */
+    /*package*/ void
+    onLocalDisconnect() {
+        if (!disconnected) {
+            doDisconnect();
+            if (Config.LOGD) Log.d(LOG_TAG,
+                    "[CDMAConn] onLoalDisconnect" );
+
+            if (parent != null) {
+                parent.detach(this);
+            }
+        }
+        releaseWakeLock();
+    }
+
     // Returns true if state has changed, false if nothing changed
     /*package*/ boolean
     update (DriverCall dc) {
@@ -587,6 +597,14 @@
     }
 
     private void
+    doDisconnect() {
+       index = -1;
+       disconnectTime = System.currentTimeMillis();
+       duration = SystemClock.elapsedRealtime() - connectTimeReal;
+       disconnected = true;
+    }
+
+    private void
     onStartedHolding() {
         holdingStartTime = SystemClock.elapsedRealtime();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 2a65de3..9d29272 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -26,22 +26,18 @@
 import android.net.NetworkInfo;
 import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
-import android.os.Handler;
 import android.os.INetStatService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.preference.PreferenceManager;
 import android.provider.Checkin;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaCellLocation;
-import android.util.EventLog;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
 
 import com.android.internal.telephony.CommandsInterface;
@@ -50,7 +46,6 @@
 import com.android.internal.telephony.DataConnection.FailCause;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.TelephonyEventLog;
 
 import java.util.ArrayList;
@@ -67,6 +62,7 @@
     // Indicates baseband will not auto-attach
     private boolean noAutoAttach = false;
     long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+    private boolean mReregisterOnReconnectFailure = false;
     private boolean mIsScreenOn = true;
 
     //useful for debugging
@@ -464,6 +460,7 @@
         startNetStatPoll();
         // reset reconnect timer
         nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+        mReregisterOnReconnectFailure = false;
     }
 
     private void resetPollStats() {
@@ -619,6 +616,21 @@
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
         if (state == State.FAILED) {
+            if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
+                if (mReregisterOnReconnectFailure) {
+                    // We have already tried to re-register to the network.
+                    // This might be a problem with the data network.
+                    nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
+                } else {
+                    // Try to Re-register to the network.
+                    Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
+                    mReregisterOnReconnectFailure = true;
+                    mCdmaPhone.mSST.reRegisterNetwork(null);
+                    nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                    return;
+                }
+            }
+
             Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -634,9 +646,6 @@
 
             // double it for next time
             nextReconnectDelay *= 2;
-            if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
-                nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
-            }
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification "
@@ -716,6 +725,7 @@
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
         nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+        mReregisterOnReconnectFailure = false;
 
         if (phone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -793,6 +803,7 @@
         } else {
             // reset reconnect timer
             nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+            mReregisterOnReconnectFailure = false;
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED);
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 2b4a700..ecdc8f6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -20,11 +20,14 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ContentValues;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.os.AsyncResult;
 import android.os.Message;
+import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
+import android.preference.PreferenceManager;
 import android.util.Config;
 import android.util.Log;
 
@@ -64,17 +67,12 @@
         Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
     }
 
-    /**
-     * Dispatches an incoming SMS messages.
-     *
-     * @param smsb the incoming message from the phone
-     */
-    protected void dispatchMessage(SmsMessageBase smsb) {
+    /** {@inheritDoc} */
+    protected int dispatchMessage(SmsMessageBase smsb) {
 
         // If sms is null, means there was a parsing error.
-        // TODO: Should NAK this.
         if (smsb == null) {
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
 
         // Decode BD stream and set sms variables.
@@ -83,27 +81,6 @@
         int teleService = sms.getTeleService();
         boolean handled = false;
 
-        // Teleservices W(E)MT and VMN are handled together:
-        if ((teleService == SmsEnvelope.TELESERVICE_WMT)
-                || (teleService == SmsEnvelope.TELESERVICE_WEMT)
-                || (teleService == SmsEnvelope.TELESERVICE_VMN)) {
-            // From here on we need decoded BD.
-            // Special case the message waiting indicator messages
-            if (sms.isMWISetMessage()) {
-                mCdmaPhone.updateMessageWaitingIndicator(true);
-                handled |= sms.isMwiDontStore();
-                if (Config.LOGD) {
-                    Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
-                }
-            } else if (sms.isMWIClearMessage()) {
-                mCdmaPhone.updateMessageWaitingIndicator(false);
-                handled |= sms.isMwiDontStore();
-                if (Config.LOGD) {
-                    Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
-                }
-            }
-        }
-
         if (sms.getUserData() == null) {
             if (Config.LOGD) {
                 Log.d(TAG, "Received SMS without user data");
@@ -111,11 +88,25 @@
             handled = true;
         }
 
-        if (handled) return;
+        if (handled) {
+            return Intents.RESULT_SMS_HANDLED;
+        }
 
         if (SmsEnvelope.TELESERVICE_WAP == teleService){
-            processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress());
-            return;
+            return processCdmaWapPdu(sms.getUserData(), sms.messageRef,
+                    sms.getOriginatingAddress());
+        } else if (SmsEnvelope.TELESERVICE_VMN == teleService) {
+            // handling Voicemail
+            int voicemailCount = sms.getNumOfVoicemails();
+            Log.d(TAG, "Voicemail count=" + voicemailCount);
+            // Store the voicemail count in preferences.
+            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+                    ((CDMAPhone) mPhone).getContext());
+            SharedPreferences.Editor editor = sp.edit();
+            editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
+            editor.commit();
+            ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
+            return Intents.RESULT_SMS_HANDLED;
         }
 
         /**
@@ -145,17 +136,19 @@
             if (smsHeader != null && smsHeader.portAddrs != null) {
                 if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
                     // GSM-style WAP indication
-                    mWapPush.dispatchWapPdu(sms.getUserData());
+                    return mWapPush.dispatchWapPdu(sms.getUserData());
+                } else {
+                    // The message was sent to a port, so concoct a URI for it.
+                    dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
                 }
-                // The message was sent to a port, so concoct a URI for it.
-                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
             } else {
                 // Normal short and non-port-addressed message, dispatch it.
                 dispatchPdus(pdus);
             }
+            return Activity.RESULT_OK;
         } else {
             // Process the message part.
-            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
+            return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
         }
     }
 
@@ -165,29 +158,35 @@
      * WDP segments are gathered until a datagram completes and gets dispatched.
      *
      * @param pdu The WAP-WDP PDU segment
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
+    protected int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
         int segment;
         int totalSegments;
         int index = 0;
         int msgType;
 
-        int sourcePort;
-        int destinationPort;
+        int sourcePort = 0;
+        int destinationPort = 0;
 
         msgType = pdu[index++];
         if (msgType != 0){
             Log.w(TAG, "Received a WAP SMS which is not WDP. Discard.");
-            return;
+            return Intents.RESULT_SMS_HANDLED;
         }
         totalSegments = pdu[index++]; // >=1
         segment = pdu[index++]; // >=0
 
-        //process WDP segment
-        sourcePort = (0xFF & pdu[index++]) << 8;
-        sourcePort |= 0xFF & pdu[index++];
-        destinationPort = (0xFF & pdu[index++]) << 8;
-        destinationPort |= 0xFF & pdu[index++];
+        // Only the first segment contains sourcePort and destination Port
+        if (segment == 0) {
+            //process WDP segment
+            sourcePort = (0xFF & pdu[index++]) << 8;
+            sourcePort |= 0xFF & pdu[index++];
+            destinationPort = (0xFF & pdu[index++]) << 8;
+            destinationPort |= 0xFF & pdu[index++];
+        }
 
         // Lookup all other related parts
         StringBuilder where = new StringBuilder("reference_number =");
@@ -217,7 +216,7 @@
 
                 mResolver.insert(mRawUri, values);
 
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
 
             // All the parts are in place, deal with them
@@ -228,6 +227,11 @@
             for (int i = 0; i < cursorCount; i++) {
                 cursor.moveToNext();
                 int cursorSequence = (int)cursor.getLong(sequenceColumn);
+                // Read the destination port from the first segment
+                if (cursorSequence == 0) {
+                    int destinationPortColumn = cursor.getColumnIndex("destination_port");
+                    destinationPort = (int)cursor.getLong(destinationPortColumn);
+                }
                 pdus[cursorSequence] = HexDump.hexStringToByteArray(
                         cursor.getString(pduColumn));
             }
@@ -237,7 +241,7 @@
             mResolver.delete(mRawUri, where.toString(), whereArgs);
         } catch (SQLException e) {
             Log.e(TAG, "Can't access multipart SMS database", e);
-            return;  // TODO: NACK the message or something, don't just discard.
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         } finally {
             if (cursor != null) cursor.close();
         }
@@ -257,15 +261,14 @@
         switch (destinationPort) {
         case SmsHeader.PORT_WAP_PUSH:
             // Handle the PUSH
-            mWapPush.dispatchWapPdu(datagram);
-            break;
+            return mWapPush.dispatchWapPdu(datagram);
 
         default:{
             pdus = new byte[1][];
             pdus[0] = datagram;
             // The messages were sent to any other WAP port
             dispatchPortAddressedPdus(pdus, destinationPort);
-            break;
+            return Activity.RESULT_OK;
         }
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
index 925a755..44958e9 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
@@ -22,6 +22,9 @@
 import android.media.ToneGenerator;
 
 public class SignalToneUtil {
+    /** A marker that isn't a valid TONE */
+    public static final int CDMA_INVALID_TONE = -1;
+
     // public final int int IS95_CONST_IR_SIGNAL_TYPE_TYPE;
     static public final int IS95_CONST_IR_SIGNAL_TONE = 0;
     static public final int IS95_CONST_IR_SIGNAL_ISDN = 1;
@@ -76,7 +79,7 @@
     private static Integer signalParamHash(int signalType, int alertPitch, int signal) {
         if ((signalType < 0) || (signalType > 256) || (alertPitch > 256) ||
                 (alertPitch < 0) || (signal > 256) || (signal < 0)) {
-            return new Integer(ToneGenerator.TONE_CDMA_INVALID);
+            return new Integer(CDMA_INVALID_TONE);
         }
         return new Integer(signalType * 256 * 256 + alertPitch * 256 + signal);
     }
@@ -84,7 +87,7 @@
     public static int getAudioToneFromSignalInfo(int signalType, int alertPitch, int signal) {
         Integer result = hm.get(signalParamHash(signalType, alertPitch, signal));
         if (result == null) {
-            return ToneGenerator.TONE_CDMA_INVALID;
+            return CDMA_INVALID_TONE;
         }
         return result;
     }
@@ -100,13 +103,13 @@
                         ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP);
 
         hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
-                IS95_CONST_IR_SIG_ISDN_SP_PRI), ToneGenerator.TONE_CDMA_CALL_SIGNAL_SP_PRI);
+                IS95_CONST_IR_SIG_ISDN_SP_PRI), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI);
 
         hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
                 IS95_CONST_IR_SIG_ISDN_PAT_3), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT3);
 
         hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
-                IS95_CONST_IR_SIG_ISDN_PING), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_RING_RING);
+                IS95_CONST_IR_SIG_ISDN_PING), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING);
 
         hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
                 IS95_CONST_IR_SIG_ISDN_PAT_5), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT5);
@@ -163,7 +166,7 @@
                 IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_HIGH_L);
 
         hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
-                IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_INVALID);
+                IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_MED_L);
 
         hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
                 IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_LOW_L);
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 63d2c47..3a92064 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -773,6 +773,12 @@
         return asciiDigit;
     }
 
+    /** This function  shall be called to get the number of voicemails.
+     * @hide
+     */
+    /*package*/ int getNumOfVoicemails() {
+        return mBearerData.numberOfMessages;
+    }
 
 
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index a835dee..03bdbda 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -789,7 +789,7 @@
         if (inStream.read(8) != 3) {
             throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect");
         }
-        bData.messageType = inStream.read(4);
+        bData.messageType = (byte)inStream.read(4);
         bData.messageId = inStream.read(8) << 8;
         bData.messageId |= inStream.read(8);
         bData.hasUserDataHeader = (inStream.read(1) == 1);
@@ -799,7 +799,7 @@
     private static void decodeUserData(BearerData bData, BitwiseInputStream inStream)
         throws BitwiseInputStream.AccessException
     {
-        byte paramBytes = inStream.read(8);
+        int paramBytes = inStream.read(8);
         bData.userData = new UserData();
         bData.userData.msgEncoding = inStream.read(5);
         bData.userData.msgEncodingSet = true;
@@ -867,7 +867,7 @@
             inStream.skip(offset);
             byte[] expandedData = new byte[numFields];
             for (int i = 0; i < numFields; i++) {
-                expandedData[i] = inStream.read(7);
+                expandedData[i] = (byte)inStream.read(7);
             }
             return new String(expandedData, 0, numFields, "US-ASCII");
         } catch (java.io.UnsupportedEncodingException ex) {
@@ -922,7 +922,7 @@
     private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
         throws BitwiseInputStream.AccessException, CodingException
     {
-        byte paramBytes = inStream.read(8);
+        int paramBytes = inStream.read(8);
         if (paramBytes != 1) {
             throw new CodingException("REPLY_OPTION subparam size incorrect");
         }
@@ -985,18 +985,18 @@
     private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
         throws BitwiseInputStream.AccessException, CodingException
     {
-        byte paramBytes = inStream.read(8);
+        int paramBytes = inStream.read(8);
         CdmaSmsAddress addr = new CdmaSmsAddress();
-        addr.digitMode = inStream.read(1);
+        addr.digitMode = (byte)inStream.read(1);
         byte fieldBits = 4;
         byte consumedBits = 1;
         if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
             addr.ton = inStream.read(3);
-            addr.numberPlan = inStream.read(4);
+            addr.numberPlan = (byte)inStream.read(4);
             fieldBits = 8;
             consumedBits += 7;
         }
-        addr.numberOfDigits = inStream.read(8);
+        addr.numberOfDigits = (byte)inStream.read(8);
         consumedBits += 8;
         int remainingBits = (paramBytes * 8) - consumedBits;
         int dataBits = addr.numberOfDigits * fieldBits;
@@ -1076,7 +1076,7 @@
         if (inStream.read(8) != 1) {
             throw new CodingException("PRIVACY_INDICATOR subparam size incorrect");
         }
-        bData.privacy = inStream.read(2);
+        bData.privacy = (byte)inStream.read(2);
         inStream.skip(6);
         bData.privacyIndicatorSet = true;
     }
@@ -1097,7 +1097,7 @@
         if (inStream.read(8) != 1) {
             throw new CodingException("DISPLAY_MODE subparam size incorrect");
         }
-        bData.displayMode = inStream.read(2);
+        bData.displayMode = (byte)inStream.read(2);
         inStream.skip(6);
         bData.displayModeSet = true;
     }
@@ -1108,7 +1108,7 @@
         if (inStream.read(8) != 1) {
             throw new CodingException("PRIORITY_INDICATOR subparam size incorrect");
         }
-        bData.priority = inStream.read(2);
+        bData.priority = (byte)inStream.read(2);
         inStream.skip(6);
         bData.priorityIndicatorSet = true;
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 70d71fc..d1e4b4f 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -448,11 +448,6 @@
     }
 
     public void
-    notifyMessageWaitingIndicator() {
-        mNotifier.notifyMessageWaitingChanged(this);
-    }
-
-    public void
     notifyCallForwardingIndicator() {
         mNotifier.notifyCallForwardingChanged(this);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 035c690..346944a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -65,6 +65,7 @@
     private static final String LOG_TAG = "GSM";
     private static final boolean DBG = true;
 
+    private GSMPhone mGsmPhone;
     /**
      * Handles changes to the APN db.
      */
@@ -85,6 +86,7 @@
     // Indicates baseband will not auto-attach
     private boolean noAutoAttach = false;
     long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+    private boolean mReregisterOnReconnectFailure = false;
     private ContentResolver mResolver;
 
     private boolean mPingTestActive = false;
@@ -204,6 +206,7 @@
 
     GsmDataConnectionTracker(GSMPhone p) {
         super(p);
+        mGsmPhone = p;
 
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
@@ -250,16 +253,16 @@
         //Unregister for all events
         phone.mCM.unregisterForAvailable(this);
         phone.mCM.unregisterForOffOrNotAvailable(this);
-        ((GSMPhone) phone).mSIMRecords.unregisterForRecordsLoaded(this);
+        mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this);
         phone.mCM.unregisterForDataStateChanged(this);
-        ((GSMPhone) phone).mCT.unregisterForVoiceCallEnded(this);
-        ((GSMPhone) phone).mCT.unregisterForVoiceCallStarted(this);
-        ((GSMPhone) phone).mSST.unregisterForGprsAttached(this);
-        ((GSMPhone) phone).mSST.unregisterForGprsDetached(this);
-        ((GSMPhone) phone).mSST.unregisterForRoamingOn(this);
-        ((GSMPhone) phone).mSST.unregisterForRoamingOff(this);
-        ((GSMPhone) phone).mSST.unregisterForPsRestrictedEnabled(this);
-        ((GSMPhone) phone).mSST.unregisterForPsRestrictedDisabled(this);
+        mGsmPhone.mCT.unregisterForVoiceCallEnded(this);
+        mGsmPhone.mCT.unregisterForVoiceCallStarted(this);
+        mGsmPhone.mSST.unregisterForGprsAttached(this);
+        mGsmPhone.mSST.unregisterForGprsDetached(this);
+        mGsmPhone.mSST.unregisterForRoamingOn(this);
+        mGsmPhone.mSST.unregisterForRoamingOff(this);
+        mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this);
+        mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this);
 
         phone.getContext().unregisterReceiver(this.mIntentReceiver);
         phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver);
@@ -407,8 +410,8 @@
     public boolean isDataConnectionAsDesired() {
         boolean roaming = phone.getServiceState().getRoaming();
 
-        if (((GSMPhone) phone).mSIMRecords.getRecordsLoaded() &&
-                ((GSMPhone) phone).mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
+        if (mGsmPhone.mSIMRecords.getRecordsLoaded() &&
+                mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
                 (!roaming || getDataOnRoamingEnabled()) &&
             !mIsWifiConnected &&
             !mIsPsRestricted ) {
@@ -572,13 +575,13 @@
             return true;
         }
 
-        int gprsState = ((GSMPhone) phone).mSST.getCurrentGprsState();
+        int gprsState = mGsmPhone.mSST.getCurrentGprsState();
         boolean roaming = phone.getServiceState().getRoaming();
-        boolean desiredPowerState = ((GSMPhone) phone).mSST.getDesiredPowerState();
+        boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState();
 
         if ((state == State.IDLE || state == State.SCANNING)
                 && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
-                && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded()
+                && mGsmPhone.mSIMRecords.getRecordsLoaded()
                 && phone.getState() == Phone.State.IDLE
                 && isDataAllowed()
                 && !mIsPsRestricted
@@ -604,8 +607,8 @@
                 log("trySetupData: Not ready for data: " +
                     " dataState=" + state +
                     " gprsState=" + gprsState +
-                    " sim=" + ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() +
-                    " UMTS=" + ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() +
+                    " sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() +
+                    " UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() +
                     " phoneState=" + phone.getState() +
                     " dataEnabled=" + getAnyDataEnabled() +
                     " roaming=" + roaming +
@@ -792,7 +795,7 @@
         isConnected = (state != State.IDLE && state != State.FAILED);
 
         // The "current" may no longer be valid.  MMS depends on this to send properly.
-        ((GSMPhone) phone).updateCurrentCarrierInProvider();
+        mGsmPhone.updateCurrentCarrierInProvider();
 
         // TODO: It'd be nice to only do this if the changed entrie(s)
         // match the current operator.
@@ -802,6 +805,7 @@
             if (!isConnected) {
                 // reset reconnect timer
                 nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                mReregisterOnReconnectFailure = false;
                 trySetupData(Phone.REASON_APN_CHANGED);
             }
         }
@@ -882,6 +886,7 @@
         startNetStatPoll();
         // reset reconnect timer
         nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+        mReregisterOnReconnectFailure = false;
     }
 
     private void setupDnsProperties() {
@@ -952,7 +957,7 @@
             } else {
                 mPdpResetCount = 0;
                 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv);
-                ((GSMPhone) phone).mSST.reRegisterNetwork(null);
+                mGsmPhone.mSST.reRegisterNetwork(null);
             }
             // TODO: Add increasingly drastic recovery steps, eg,
             // reset the radio, reset the device.
@@ -1166,6 +1171,20 @@
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
         if (state == State.FAILED) {
+            if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
+                if (mReregisterOnReconnectFailure) {
+                    // We have already tried to re-register to the network.
+                    // This might be a problem with the data network.
+                    nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
+                } else {
+                    // Try to Re-register to the network.
+                    Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
+                    mReregisterOnReconnectFailure = true;
+                    mGsmPhone.mSST.reRegisterNetwork(null);
+                    nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                    return;
+                }
+            }
             Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -1181,9 +1200,6 @@
 
             // double it for next time
             nextReconnectDelay *= 2;
-            if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
-                nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
-            }
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification "
@@ -1258,6 +1274,7 @@
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
         nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+        mReregisterOnReconnectFailure = false;
 
         if (phone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -1370,7 +1387,7 @@
     }
 
     protected void onVoiceCallStarted() {
-        if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) {
+        if (state == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) {
             stopNetStatPoll();
             phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
         }
@@ -1378,7 +1395,7 @@
 
     protected void onVoiceCallEnded() {
         if (state == State.CONNECTED) {
-            if (!((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) {
+            if (mGsmPhone.mSST.isConcurrentVoiceAndData()) {
                 startNetStatPoll();
                 phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
             } else {
@@ -1388,6 +1405,7 @@
         } else {
             // reset reconnect timer
             nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+            mReregisterOnReconnectFailure = false;
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED);
         }
@@ -1417,7 +1435,7 @@
      */
     private void createAllApnList() {
         allApns = new ArrayList<ApnSetting>();
-        String operator = ((GSMPhone) phone).mSIMRecords.getSIMOperatorNumeric();
+        String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
@@ -1459,7 +1477,7 @@
         DataConnection pdp;
 
         for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
-            pdp = new PdpConnection((GSMPhone) phone);
+            pdp = new PdpConnection(mGsmPhone);
             pdpList.add(pdp);
          }
     }
@@ -1478,7 +1496,7 @@
      */
     private ArrayList<ApnSetting> buildWaitingApns() {
         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
-        String operator = ((GSMPhone )phone).mSIMRecords.getSIMOperatorNumeric();
+        String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && preferredApn != null) {
@@ -1664,6 +1682,7 @@
                     if (state == State.FAILED) {
                         cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
                         nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                        mReregisterOnReconnectFailure = false;
                     }
                     trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
                 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index f87392a..2770ddc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -78,24 +78,16 @@
                 }
             }
         }
-
-        if (mCm != null) {
-            mCm.acknowledgeLastIncomingGsmSms(true, Intents.RESULT_SMS_HANDLED, null);
-        }
+        acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null);
     }
 
 
-    /**
-     * Dispatches an incoming SMS messages.
-     *
-     * @param sms the incoming message from the phone
-     */
-    protected void dispatchMessage(SmsMessageBase smsb) {
+    /** {@inheritDoc} */
+    protected int dispatchMessage(SmsMessageBase smsb) {
 
         // If sms is null, means there was a parsing error.
-        // TODO: Should NAK this.
         if (smsb == null) {
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         SmsMessage sms = (SmsMessage) smsb;
         boolean handled = false;
@@ -115,7 +107,9 @@
             }
         }
 
-        if (handled) return;
+        if (handled) {
+            return Intents.RESULT_SMS_HANDLED;
+        }
 
         SmsHeader smsHeader = sms.getUserDataHeader();
          // See if message is partial or port addressed.
@@ -126,17 +120,19 @@
 
             if (smsHeader != null && smsHeader.portAddrs != null) {
                 if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
-                    mWapPush.dispatchWapPdu(sms.getUserData());
+                    return mWapPush.dispatchWapPdu(sms.getUserData());
+                } else {
+                    // The message was sent to a port, so concoct a URI for it.
+                    dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
                 }
-                // The message was sent to a port, so concoct a URI for it.
-                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
             } else {
                 // Normal short and non-port-addressed message, dispatch it.
                 dispatchPdus(pdus);
             }
+            return Activity.RESULT_OK;
         } else {
             // Process the message part.
-            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
+            return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
         }
     }
 
diff --git a/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.java b/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.java
index a935247..c5562b3 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.java
@@ -25,6 +25,8 @@
 
 import android.util.Log;
 
+import java.util.Random;
+
 public class BitwiseStreamsTest extends AndroidTestCase {
     private final static String LOG_TAG = "BitwiseStreamsTest";
 
@@ -39,7 +41,7 @@
         BitwiseInputStream inStream = new BitwiseInputStream(outBuf);
         byte[] inBufDup = new byte[inBuf.length];
         inStream.skip(offset);
-        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
+        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = (byte)inStream.read(8);
         assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
     }
 
@@ -53,7 +55,7 @@
         BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
         inStream.skip(offset);
         byte[] inBufDup = new byte[inBuf.length];
-        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
+        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = (byte)inStream.read(8);
         assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
     }
 
@@ -67,7 +69,7 @@
         BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
         inStream.skip(offset);
         byte[] inBufDup = new byte[inBuf.length];
-        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
+        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = (byte)inStream.read(8);
         assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
     }
 
@@ -84,12 +86,33 @@
         BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
         inStream.skip(offset);
         byte[] inBufDup = new byte[inBuf.length];
-        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
+        for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = (byte)inStream.read(8);
         assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
     }
 
     @SmallTest
     public void testFive() throws Exception {
+        Random random = new Random();
+        int iterations = 10000;
+        int[] sizeArr = new int[iterations];
+        int[] valueArr = new int[iterations];
+        BitwiseOutputStream outStream = new BitwiseOutputStream(iterations * 4);
+        for (int i = 0; i < iterations; i++) {
+            int x = random.nextInt();
+            int size = (x & 0x07) + 1;
+            int value = x & (-1 >>> (32 - size));
+            sizeArr[i] = size;
+            valueArr[i] = value;
+            outStream.write(size, value);
+        }
+        BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
+        for (int i = 0; i < iterations; i++) {
+            assertEquals(valueArr[i], inStream.read(sizeArr[i]));
+        }
+    }
+
+    @SmallTest
+    public void testSix() throws Exception {
         int num_runs = 10;
         long start = android.os.SystemClock.elapsedRealtime();
         for (int run = 0; run < num_runs; run++) {
@@ -104,7 +127,7 @@
             BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
             inStream.skip(offset);
             byte[] inBufDup = new byte[inBuf.length];
-            for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
+            for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = (byte)inStream.read(8);
             assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
         }
         long end = android.os.SystemClock.elapsedRealtime();
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index b2529811..9188e04b 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -171,14 +171,14 @@
         assertEquals(bearerData.msgCenterTimeStamp.minute, 1);
         assertEquals(bearerData.msgCenterTimeStamp.second, 59);
         assertEquals(bearerData.validityPeriodAbsolute, null);
-        assertEquals(bearerData.validityPeriodRelative, -63);
+        assertEquals(bearerData.validityPeriodRelative, 193);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.year, 1997);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.month, 5);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.monthDay, 18);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.hour, 0);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.minute, 0);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.second, 0);
-        assertEquals(bearerData.deferredDeliveryTimeRelative, -57);
+        assertEquals(bearerData.deferredDeliveryTimeRelative, 199);
         assertEquals(bearerData.hasUserDataHeader, false);
         assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII);
         assertEquals(bearerData.userData.numFields, 2);
@@ -225,7 +225,7 @@
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.hour, 0);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.minute, 0);
         assertEquals(bearerData.deferredDeliveryTimeAbsolute.second, 0);
-        assertEquals(bearerData.deferredDeliveryTimeRelative, -110);
+        assertEquals(bearerData.deferredDeliveryTimeRelative, 146);
         assertEquals(bearerData.hasUserDataHeader, false);
         assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII);
         assertEquals(bearerData.userData.numFields, 2);
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
index f71cff2..64ad7be 100644
--- a/tests/DpiTest/AndroidManifest.xml
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -16,6 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.google.android.test.dpi">
+    <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="3" />
+    <supports-screens android:smallScreens="true" />
     <application android:label="DpiTest">
         <activity android:name="DpiTestActivity" android:label="DpiTest">
             <intent-filter>
diff --git a/tests/DpiTest/res/values-largeScreen/strings.xml b/tests/DpiTest/res/values-largeScreen/strings.xml
new file mode 100644
index 0000000..f4dd543
--- /dev/null
+++ b/tests/DpiTest/res/values-largeScreen/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+    <string name="act_title">DpiTest: Large Screen</string>
+</resources>
diff --git a/tests/DpiTest/res/values-normalScreen/strings.xml b/tests/DpiTest/res/values-normalScreen/strings.xml
new file mode 100644
index 0000000..256d696
--- /dev/null
+++ b/tests/DpiTest/res/values-normalScreen/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+    <string name="act_title">DpiTest: Normal Screen</string>
+</resources>
diff --git a/tests/DpiTest/res/values-smallScreen/strings.xml b/tests/DpiTest/res/values-smallScreen/strings.xml
new file mode 100644
index 0000000..cdb4ac9
--- /dev/null
+++ b/tests/DpiTest/res/values-smallScreen/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+    <string name="act_title">DpiTest: Small Screen</string>
+</resources>
diff --git a/tests/DpiTest/res/values/strings.xml b/tests/DpiTest/res/values/strings.xml
new file mode 100644
index 0000000..ef924ac
--- /dev/null
+++ b/tests/DpiTest/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+    <string name="act_title">DpiTest: Unknown Screen</string>
+</resources>
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 3759622..5a9f3f5 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -34,6 +34,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        this.setTitle(R.string.act_title);
         LinearLayout root = new LinearLayout(this);
         root.setOrientation(LinearLayout.VERTICAL);
 
diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
index c6acc66..8e4fd39 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
@@ -18,11 +18,15 @@
 
 import android.backup.BackupHelperAgent;
 import android.backup.FileBackupHelper;
+import android.backup.SharedPreferencesBackupHelper;
 
 public class BackupTestAgent extends BackupHelperAgent
 {
     public void onCreate() {
         addHelper("data_files", new FileBackupHelper(this, BackupTestActivity.FILE_NAME));
+        addHelper("more_data_files", new FileBackupHelper(this, "another_file.txt", "3.txt",
+                    "empty.txt"));
+        addHelper("shared_prefs", new SharedPreferencesBackupHelper(this, "settings", "raw"));
     }
 }
 
diff --git a/tests/backup/test_backup.sh b/tests/backup/test_backup.sh
new file mode 100755
index 0000000..dbf9ed2
--- /dev/null
+++ b/tests/backup/test_backup.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+#adb kill-server
+
+# set the transport
+adb shell bmgr transport 1
+
+# load up the three files
+adb shell "rm /data/data/com.android.backuptest/files/* ; \
+           mkdir /data/data/com.android.backuptest ; \
+           mkdir /data/data/com.android.backuptest/files ; \
+           mkdir /data/data/com.android.backuptest/shared_prefs ; \
+           echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" > /data/data/com.android.backuptest/shared_prefs/raw.xml ; \
+           echo -n first file > /data/data/com.android.backuptest/files/file.txt ; \
+           echo -n asdf > /data/data/com.android.backuptest/files/another_file.txt ; \
+           echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
+           echo -n "" > /data/data/com.android.backuptest/files/empty.txt ; \
+"
+
+# say that the data has changed
+adb shell bmgr backup com.android.backuptest
+
+# run the backup
+adb shell bmgr run
+
+
+
diff --git a/tests/backup/test_restore.sh b/tests/backup/test_restore.sh
new file mode 100755
index 0000000..ccf29cf
--- /dev/null
+++ b/tests/backup/test_restore.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+function check_file
+{
+    data=$(adb shell cat /data/data/com.android.backuptest/$1)
+    if [ "$data" = "$2" ] ; then
+        echo "$1 has correct value [$2]"
+    else
+        echo $1 is INCORRECT
+        echo "   value:    [$data]"
+        echo "   expected: [$2]"
+    fi
+}
+
+# delete the old data
+echo --- Previous files
+adb shell "ls -l /data/data/com.android.backuptest/files"
+adb shell "rm /data/data/com.android.backuptest/files/*"
+echo --- Previous shared_prefs
+adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+adb shell "rm /data/data/com.android.backuptest/shared_prefs/*"
+echo --- Erased files and shared_prefs
+adb shell "ls -l /data/data/com.android.backuptest/files"
+adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+echo ---
+
+echo
+echo
+echo
+
+# run the restore
+adb shell bmgr restore 0
+
+echo
+echo
+echo
+
+# check the results
+check_file files/file.txt "first file"
+check_file files/another_file.txt "asdf"
+check_file files/3.txt "3"
+check_file files/empty.txt ""
+check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>'
+
+echo
+echo
+echo
+echo --- Restored files
+adb shell "ls -l /data/data/com.android.backuptest/files"
+echo --- Restored shared_prefs
+adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+echo ---
+echo
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 6bc1ee6..67af116 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -187,6 +187,13 @@
         return 0;
     }
 
+    // screen layout
+    if (getScreenLayoutName(part.string(), &config)) {
+        *axis = AXIS_SCREENLAYOUT;
+        *value = config.screenLayout;
+        return 0;
+    }
+
     // version
     if (getVersionName(part.string(), &config)) {
         *axis = AXIS_VERSION;
@@ -202,7 +209,7 @@
 {
     Vector<String8> parts;
 
-    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, vers;
+    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers;
 
     const char *p = dir;
     const char *q;
@@ -378,6 +385,18 @@
         //printf("not screen size: %s\n", part.string());
     }
 
+    if (getScreenLayoutName(part.string())) {
+        layout = part;
+
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index];
+    } else {
+        //printf("not screen layout: %s\n", part.string());
+    }
+
     if (getVersionName(part.string())) {
         vers = part;
 
@@ -404,6 +423,7 @@
     this->keyboard = key;
     this->navigation = nav;
     this->screenSize = size;
+    this->screenLayout = layout;
     this->version = vers;
 
     // what is this anyway?
@@ -435,6 +455,8 @@
     s += ",";
     s += screenSize;
     s += ",";
+    s += screenLayout;
+    s += ",";
     s += version;
     return s;
 }
@@ -483,6 +505,10 @@
         s += "-";
         s += screenSize;
     }
+    if (this->screenLayout != "") {
+        s += "-";
+        s += screenLayout;
+    }
     if (this->version != "") {
         s += "-";
         s += version;
@@ -786,6 +812,26 @@
     return true;
 }
 
+bool AaptGroupEntry::getScreenLayoutName(const char* name,
+                                     ResTable_config* out)
+{
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_ANY;
+        return true;
+    } else if (strcmp(name, "smallscreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_SMALL;
+        return true;
+    } else if (strcmp(name, "normalscreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL;
+        return true;
+    } else if (strcmp(name, "largescreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_LARGE;
+        return true;
+    }
+
+    return false;
+}
+
 bool AaptGroupEntry::getVersionName(const char* name,
                                     ResTable_config* out)
 {
@@ -828,6 +874,7 @@
     if (v == 0) v = keyboard.compare(o.keyboard);
     if (v == 0) v = navigation.compare(o.navigation);
     if (v == 0) v = screenSize.compare(o.screenSize);
+    if (v == 0) v = screenLayout.compare(o.screenLayout);
     if (v == 0) v = version.compare(o.version);
     return v;
 }
@@ -846,6 +893,7 @@
     getKeyboardName(keyboard.string(), &params);
     getNavigationName(navigation.string(), &params);
     getScreenSizeName(screenSize.string(), &params);
+    getScreenLayoutName(screenLayout.string(), &params);
     getVersionName(version.string(), &params);
     return params;
 }
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 01c8140..3b96412 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -37,6 +37,7 @@
     AXIS_KEYBOARD,
     AXIS_NAVIGATION,
     AXIS_SCREENSIZE,
+    AXIS_SCREENLAYOUT,
     AXIS_VERSION
 };
 
@@ -62,6 +63,7 @@
     String8 keyboard;
     String8 navigation;
     String8 screenSize;
+    String8 screenLayout;
     String8 version;
 
     bool initFromDirName(const char* dir, String8* resType);
@@ -78,6 +80,7 @@
     static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
     static bool getNavigationName(const char* name, ResTable_config* out = NULL);
     static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
+    static bool getScreenLayoutName(const char* name, ResTable_config* out = NULL);
     static bool getVersionName(const char* name, ResTable_config* out = NULL);
 
     int compare(const AaptGroupEntry& o) const;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 503f661..e04491d 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -329,6 +329,9 @@
     TARGET_SDK_VERSION_ATTR = 0x01010270,
     TEST_ONLY_ATTR = 0x01010272,
     DENSITY_ATTR = 0x0101026c,
+    SMALL_SCREEN_ATTR = 0x01010284,
+    NORMAL_SCREEN_ATTR = 0x01010285,
+    LARGE_SCREEN_ATTR = 0x01010286,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -499,6 +502,10 @@
             bool isLauncherActivity = false;
             bool withinApplication = false;
             bool withinReceiver = false;
+            int targetSdk = 0;
+            int smallScreen = 1;
+            int normalScreen = 1;
+            int largeScreen = 1;
             String8 pkg;
             String8 activityName;
             String8 activityLabel;
@@ -572,8 +579,10 @@
                                         error.string());
                                 goto bail;
                             }
+                            if (name == "Donut") targetSdk = 4;
                             printf("sdkVersion:'%s'\n", name.string());
                         } else if (code != -1) {
+                            targetSdk = code;
                             printf("sdkVersion:'%d'\n", code);
                         }
                         code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
@@ -585,8 +594,12 @@
                                         error.string());
                                 goto bail;
                             }
+                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
                             printf("targetSdkVersion:'%s'\n", name.string());
                         } else if (code != -1) {
+                            if (targetSdk < code) {
+                                targetSdk = code;
+                            }
                             printf("targetSdkVersion:'%d'\n", code);
                         }
                     } else if (tag == "uses-configuration") {
@@ -625,6 +638,13 @@
                             goto bail;
                         }
                         printf("supports-density:'%d'\n", dens);
+                    } else if (tag == "supports-screens") {
+                        smallScreen = getIntegerAttribute(tree,
+                                SMALL_SCREEN_ATTR, NULL, 1);
+                        normalScreen = getIntegerAttribute(tree,
+                                NORMAL_SCREEN_ATTR, NULL, 1);
+                        largeScreen = getIntegerAttribute(tree,
+                                LARGE_SCREEN_ATTR, NULL, 1);
                     }
                 } else if (depth == 3 && withinApplication) {
                     withinActivity = false;
@@ -733,6 +753,25 @@
                 }
             }
             
+            // Determine default values for any unspecified screen sizes,
+            // based on the target SDK of the package.  As of 4 (donut)
+            // the screen size support was introduced, so all default to
+            // enabled.
+            if (smallScreen > 0) {
+                smallScreen = targetSdk >= 4 ? -1 : 0;
+            }
+            if (normalScreen > 0) {
+                normalScreen = -1;
+            }
+            if (largeScreen > 0) {
+                largeScreen = targetSdk >= 4 ? -1 : 0;
+            }
+            printf("supports-screens:");
+            if (smallScreen != 0) printf(" 'small'");
+            if (normalScreen != 0) printf(" 'normal'");
+            if (largeScreen != 0) printf(" 'large'");
+            printf("\n");
+            
             printf("locales:");
             Vector<String8> locales;
             res.getLocales(&locales);
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 1dedd04..aec2164 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -5,6 +5,7 @@
 #include <vector>
 #include <set>
 #include <stdarg.h>
+#include <stdio.h>
 
 using namespace std;
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
index 1fa11af..06dd96f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
@@ -59,7 +59,7 @@
     public void setConfiguration(int mcc, int mnc, String locale,
             int orientation, int touchscreen, int density, int keyboard,
             int keyboardHidden, int navigation, int screenWidth, int screenHeight,
-            int version)  {
+            int screenLayout, int version)  {
         
         Configuration c = new Configuration();
         c.mcc = mcc;
@@ -70,5 +70,6 @@
         c.keyboardHidden = keyboardHidden;
         c.navigation = navigation;
         c.orientation = orientation;
+        c.screenLayout = screenLayout;
     }
 }
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 3425668..1c644ed 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -1,6 +1,7 @@
 #include "Perforce.h"
 #include "log.h"
 #include <string.h>
+#include <cstdio>
 #include <stdlib.h>
 #include <sstream>
 #include <sys/types.h>
diff --git a/tools/localize/SourcePos.cpp b/tools/localize/SourcePos.cpp
index 9d7c5c6..2533f0a 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -1,6 +1,7 @@
 #include "SourcePos.h"
 
 #include <stdarg.h>
+#include <cstdio>
 #include <set>
 
 using namespace std;
diff --git a/tools/localize/Values.cpp b/tools/localize/Values.cpp
index e396f8b..8623b97 100644
--- a/tools/localize/Values.cpp
+++ b/tools/localize/Values.cpp
@@ -1,5 +1,6 @@
 #include "Values.h"
 #include <stdlib.h>
+#include <cstdio>
 
 
 // =====================================================================================
diff --git a/tools/localize/XLIFFFile.cpp b/tools/localize/XLIFFFile.cpp
index 51f81de..4e217d9 100644
--- a/tools/localize/XLIFFFile.cpp
+++ b/tools/localize/XLIFFFile.cpp
@@ -3,6 +3,7 @@
 #include <algorithm>
 #include <sys/time.h>
 #include <time.h>
+#include <cstdio>
 
 const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2";
 
diff --git a/tools/localize/file_utils.cpp b/tools/localize/file_utils.cpp
index 8792b9e..293e50e 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -1,4 +1,5 @@
 #include <string.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include "file_utils.h"
diff --git a/tools/localize/localize_test.cpp b/tools/localize/localize_test.cpp
index 63d904c..678cad8 100644
--- a/tools/localize/localize_test.cpp
+++ b/tools/localize/localize_test.cpp
@@ -1,6 +1,7 @@
 #include "XLIFFFile.h"
 #include "ValuesFile.h"
 #include "localize.h"
+#include <stdio.h>
 
 int pseudolocalize_xliff(XLIFFFile* xliff, bool expand);
 
diff --git a/tools/localize/merge_res_and_xliff.cpp b/tools/localize/merge_res_and_xliff.cpp
index 58a6554..1fdaa0e 100644
--- a/tools/localize/merge_res_and_xliff.cpp
+++ b/tools/localize/merge_res_and_xliff.cpp
@@ -3,6 +3,7 @@
 #include "file_utils.h"
 #include "Perforce.h"
 #include "log.h"
+#include <stdio.h>
 
 static set<StringResource>::const_iterator
 find_id(const set<StringResource>& s, const string& id, int index)
diff --git a/tools/localize/merge_res_and_xliff_test.cpp b/tools/localize/merge_res_and_xliff_test.cpp
index 5a2b0f4..e4ab562 100644
--- a/tools/localize/merge_res_and_xliff_test.cpp
+++ b/tools/localize/merge_res_and_xliff_test.cpp
@@ -1,5 +1,5 @@
 #include "merge_res_and_xliff.h"
-
+#include <stdio.h>
 
 int
 merge_test()
diff --git a/tools/localize/xmb.cpp b/tools/localize/xmb.cpp
index 236705f..d8f6ff0 100644
--- a/tools/localize/xmb.cpp
+++ b/tools/localize/xmb.cpp
@@ -7,6 +7,7 @@
 #include "XLIFFFile.h"
 
 #include <map>
+#include <cstdio>
 
 using namespace std;
 
diff --git a/vpn/java/android/net/vpn/IVpnService.aidl b/vpn/java/android/net/vpn/IVpnService.aidl
index 0e658df..fedccb0 100644
--- a/vpn/java/android/net/vpn/IVpnService.aidl
+++ b/vpn/java/android/net/vpn/IVpnService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/vpn/java/android/net/vpn/L2tpIpsecProfile.java b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
index 181619d..4ae2dec 100644
--- a/vpn/java/android/net/vpn/L2tpIpsecProfile.java
+++ b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
@@ -19,15 +19,14 @@
 import android.os.Parcel;
 
 /**
- * The profile for L2TP-over-IPSec type of VPN.
+ * The profile for certificate-based L2TP-over-IPSec type of VPN.
  * {@hide}
  */
-public class L2tpIpsecProfile extends VpnProfile {
+public class L2tpIpsecProfile extends L2tpProfile {
     private static final long serialVersionUID = 1L;
 
     private String mUserCertificate;
     private String mCaCertificate;
-    private String mUserkey;
 
     @Override
     public VpnType getType() {
@@ -50,20 +49,11 @@
         return mUserCertificate;
     }
 
-    public void setUserkey(String name) {
-        mUserkey = name;
-    }
-
-    public String getUserkey() {
-        return mUserkey;
-    }
-
     @Override
     protected void readFromParcel(Parcel in) {
         super.readFromParcel(in);
         mCaCertificate = in.readString();
         mUserCertificate = in.readString();
-        mUserkey = in.readString();
     }
 
     @Override
@@ -71,6 +61,5 @@
         super.writeToParcel(parcel, flags);
         parcel.writeString(mCaCertificate);
         parcel.writeString(mUserCertificate);
-        parcel.writeString(mUserkey);
     }
 }
diff --git a/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java
new file mode 100644
index 0000000..7a03018
--- /dev/null
+++ b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for pre-shared-key-based L2TP-over-IPSec type of VPN.
+ * {@hide}
+ */
+public class L2tpIpsecPskProfile extends L2tpProfile {
+    private static final long serialVersionUID = 1L;
+
+    private String mPresharedKey;
+
+    @Override
+    public VpnType getType() {
+        return VpnType.L2TP_IPSEC_PSK;
+    }
+
+    public void setPresharedKey(String key) {
+        mPresharedKey = key;
+    }
+
+    public String getPresharedKey() {
+        return mPresharedKey;
+    }
+
+    @Override
+    protected void readFromParcel(Parcel in) {
+        super.readFromParcel(in);
+        mPresharedKey = in.readString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeString(mPresharedKey);
+    }
+}
diff --git a/vpn/java/android/net/vpn/L2tpProfile.java b/vpn/java/android/net/vpn/L2tpProfile.java
index 59d4981..dbba0c5 100644
--- a/vpn/java/android/net/vpn/L2tpProfile.java
+++ b/vpn/java/android/net/vpn/L2tpProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
@@ -16,6 +16,8 @@
 
 package android.net.vpn;
 
+import android.os.Parcel;
+
 /**
  * The profile for L2TP type of VPN.
  * {@hide}
@@ -23,8 +25,44 @@
 public class L2tpProfile extends VpnProfile {
     private static final long serialVersionUID = 1L;
 
+    private boolean mSecret;
+    private String mSecretString;
+
     @Override
     public VpnType getType() {
         return VpnType.L2TP;
     }
+
+    /**
+     * Enables/disables the secret for authenticating tunnel connection.
+     */
+    public void setSecretEnabled(boolean enabled) {
+        mSecret = enabled;
+    }
+
+    public boolean isSecretEnabled() {
+        return mSecret;
+    }
+
+    public void setSecretString(String secret) {
+        mSecretString = secret;
+    }
+
+    public String getSecretString() {
+        return mSecretString;
+    }
+
+    @Override
+    protected void readFromParcel(Parcel in) {
+        super.readFromParcel(in);
+        mSecret = in.readInt() > 0;
+        mSecretString = in.readString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeInt(mSecret ? 1 : 0);
+        parcel.writeString(mSecretString);
+    }
 }
diff --git a/vpn/java/android/net/vpn/PptpProfile.java b/vpn/java/android/net/vpn/PptpProfile.java
new file mode 100644
index 0000000..c68bb71
--- /dev/null
+++ b/vpn/java/android/net/vpn/PptpProfile.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+/**
+ * The profile for PPTP type of VPN.
+ * {@hide}
+ */
+public class PptpProfile extends VpnProfile {
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public VpnType getType() {
+        return VpnType.PPTP;
+    }
+}
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index 98795bd..dc70b26 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/vpn/java/android/net/vpn/VpnProfile.aidl b/vpn/java/android/net/vpn/VpnProfile.aidl
index ad34bfc..edeaef0 100644
--- a/vpn/java/android/net/vpn/VpnProfile.aidl
+++ b/vpn/java/android/net/vpn/VpnProfile.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/vpn/java/android/net/vpn/VpnProfile.java b/vpn/java/android/net/vpn/VpnProfile.java
index 9e24da4..bd6c809 100644
--- a/vpn/java/android/net/vpn/VpnProfile.java
+++ b/vpn/java/android/net/vpn/VpnProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/vpn/java/android/net/vpn/VpnState.java b/vpn/java/android/net/vpn/VpnState.java
index 977d938..ebd9364 100644
--- a/vpn/java/android/net/vpn/VpnState.java
+++ b/vpn/java/android/net/vpn/VpnState.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
index 91b0ea2..c7df943 100644
--- a/vpn/java/android/net/vpn/VpnType.java
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * 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.
@@ -21,14 +21,21 @@
  * {@hide}
  */
 public enum VpnType {
-    L2TP_IPSEC("L2TP/IPSec", L2tpIpsecProfile.class),
-    L2TP("L2TP", L2tpProfile.class);
+    PPTP("PPTP", "", PptpProfile.class),
+    L2TP("L2TP", "", L2tpProfile.class),
+    L2TP_IPSEC_PSK("L2TP/IPSec PSK", "Pre-shared key based L2TP/IPSec VPN",
+            L2tpIpsecPskProfile.class),
+    L2TP_IPSEC("L2TP/IPSec CRT", "Certificate based L2TP/IPSec VPN",
+            L2tpIpsecProfile.class);
 
     private String mDisplayName;
+    private String mDescription;
     private Class<? extends VpnProfile> mClass;
 
-    VpnType(String displayName, Class<? extends VpnProfile> klass) {
+    VpnType(String displayName, String description,
+            Class<? extends VpnProfile> klass) {
         mDisplayName = displayName;
+        mDescription = description;
         mClass = klass;
     }
 
@@ -36,6 +43,10 @@
         return mDisplayName;
     }
 
+    public String getDescription() {
+        return mDescription;
+    }
+
     public Class<? extends VpnProfile> getProfileClass() {
         return mClass;
     }