Merge change 2572 into donut

* changes:
  Adding java/jni code for the Java TTS SynthProxy class, which relays calls from the TTS service to the native TTS plugin library.
diff --git a/Android.mk b/Android.mk
index 4df6f8e..26bcb5c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -70,6 +70,7 @@
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IActivityWatcher.aidl \
 	core/java/android/app/IAlarmManager.aidl \
+    core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
 	core/java/android/app/IIntentReceiver.aidl \
 	core/java/android/app/IIntentSender.aidl \
@@ -82,7 +83,6 @@
 	core/java/android/app/IWallpaperService.aidl \
 	core/java/android/app/IWallpaperServiceCallback.aidl \
 	core/java/android/backup/IBackupManager.aidl \
-	core/java/android/backup/IBackupService.aidl \
 	core/java/android/bluetooth/IBluetoothA2dp.aidl \
 	core/java/android/bluetooth/IBluetoothDevice.aidl \
 	core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \
diff --git a/api/current.xml b/api/current.xml
index ce1b726..d1d57ad 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -309,6 +309,17 @@
  visibility="public"
 >
 </field>
+<field name="CHANGE_WIFI_MULTICAST_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.CHANGE_WIFI_MULTICAST_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CHANGE_WIFI_STATE"
  type="java.lang.String"
  transient="false"
@@ -1156,11 +1167,11 @@
  visibility="public"
 >
 </field>
-<field name="WRITE_SDCARD"
+<field name="WRITE_EXTERNAL_STORAGE"
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.permission.WRITE_SDCARD&quot;"
+ value="&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2066,6 +2077,17 @@
  visibility="public"
 >
 </field>
+<field name="allowBackup"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843393"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="allowClearUserData"
  type="int"
  transient="false"
@@ -2297,6 +2319,17 @@
  visibility="public"
 >
 </field>
+<field name="backupAgent"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843392"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="baselineAlignBottom"
  type="int"
  transient="false"
@@ -3496,28 +3529,6 @@
  visibility="public"
 >
 </field>
-<field name="donut_resource_pad31"
- type="int"
- transient="false"
- volatile="false"
- value="16843393"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="donut_resource_pad32"
- type="int"
- transient="false"
- volatile="false"
- value="16843392"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="donut_resource_pad4"
  type="int"
  transient="false"
@@ -46393,10 +46404,75 @@
 >
 </field>
 </class>
-<class name="GestureLibrary"
+<class name="GestureLibraries"
  extends="java.lang.Object"
  abstract="false"
  static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="fromFile"
+ return="android.gesture.GestureLibrary"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="fromFile"
+ return="android.gesture.GestureLibrary"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.io.File">
+</parameter>
+</method>
+<method name="fromPrivateFile"
+ return="android.gesture.GestureLibrary"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="fromRawResource"
+ return="android.gesture.GestureLibrary"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="resourceId" type="int">
+</parameter>
+</method>
+</class>
+<class name="GestureLibrary"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
  final="false"
  deprecated="not deprecated"
  visibility="public"
@@ -46406,10 +46482,8 @@
  static="false"
  final="false"
  deprecated="not deprecated"
- visibility="public"
+ visibility="protected"
 >
-<parameter name="path" type="java.lang.String">
-</parameter>
 </constructor>
 <method name="addGesture"
  return="void"
@@ -46450,6 +46524,17 @@
 <parameter name="entryName" type="java.lang.String">
 </parameter>
 </method>
+<method name="getLearner"
+ return="android.gesture.Learner"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getOrientationStyle"
  return="int"
  abstract="false"
@@ -46472,7 +46557,7 @@
  visibility="public"
 >
 </method>
-<method name="load"
+<method name="isReadOnly"
  return="boolean"
  abstract="false"
  native="false"
@@ -46483,6 +46568,17 @@
  visibility="public"
 >
 </method>
+<method name="load"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="recognize"
  return="java.util.ArrayList&lt;android.gesture.Prediction&gt;"
  abstract="false"
@@ -46526,7 +46622,7 @@
 </method>
 <method name="save"
  return="boolean"
- abstract="false"
+ abstract="true"
  native="false"
  synchronized="false"
  static="false"
@@ -46561,48 +46657,14 @@
 <parameter name="type" type="int">
 </parameter>
 </method>
-<field name="ORIENTATION_INVARIANT"
- type="int"
+<field name="mStore"
+ type="android.gesture.GestureStore"
  transient="false"
  volatile="false"
- value="1"
- static="true"
+ static="false"
  final="true"
  deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ORIENTATION_SENSITIVE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="SEQUENCE_INVARIANT"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="SEQUENCE_SENSITIVE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
+ visibility="protected"
 >
 </field>
 </class>
@@ -47234,6 +47296,259 @@
 >
 </field>
 </class>
+<class name="GestureStore"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="GestureStore"
+ type="android.gesture.GestureStore"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addGesture"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entryName" type="java.lang.String">
+</parameter>
+<parameter name="gesture" type="android.gesture.Gesture">
+</parameter>
+</method>
+<method name="getGestureEntries"
+ return="java.util.Set&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGestures"
+ return="java.util.ArrayList&lt;android.gesture.Gesture&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entryName" type="java.lang.String">
+</parameter>
+</method>
+<method name="getOrientationStyle"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSequenceType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="load"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="stream" type="java.io.InputStream">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="load"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="stream" type="java.io.InputStream">
+</parameter>
+<parameter name="closeStream" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="recognize"
+ return="java.util.ArrayList&lt;android.gesture.Prediction&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gesture" type="android.gesture.Gesture">
+</parameter>
+</method>
+<method name="removeEntry"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entryName" type="java.lang.String">
+</parameter>
+</method>
+<method name="removeGesture"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entryName" type="java.lang.String">
+</parameter>
+<parameter name="gesture" type="android.gesture.Gesture">
+</parameter>
+</method>
+<method name="save"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="stream" type="java.io.OutputStream">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="save"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="stream" type="java.io.OutputStream">
+</parameter>
+<parameter name="closeStream" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setOrientationStyle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="style" type="int">
+</parameter>
+</method>
+<method name="setSequenceType"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="int">
+</parameter>
+</method>
+<field name="ORIENTATION_INVARIANT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_SENSITIVE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SEQUENCE_INVARIANT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SEQUENCE_SENSITIVE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="GestureStroke"
  extends="java.lang.Object"
  abstract="false"
@@ -47334,6 +47649,15 @@
 >
 </field>
 </class>
+<class name="Learner"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility=""
+>
+</class>
 <class name="LetterRecognizer"
  extends="java.lang.Object"
  abstract="false"
@@ -47342,21 +47666,6 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<method name="getLetterRecognizer"
- return="android.gesture.LetterRecognizer"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="type" type="int">
-</parameter>
-</method>
 <method name="recognize"
  return="java.util.ArrayList&lt;android.gesture.Prediction&gt;"
  abstract="false"
@@ -47385,6 +47694,84 @@
 <parameter name="predictions" type="java.util.ArrayList&lt;android.gesture.Prediction&gt;">
 </parameter>
 </method>
+</class>
+<class name="LetterRecognizers"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="fromFile"
+ return="android.gesture.LetterRecognizer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="fromFile"
+ return="android.gesture.LetterRecognizer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="file" type="java.io.File">
+</parameter>
+</method>
+<method name="fromResource"
+ return="android.gesture.LetterRecognizer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="resourceId" type="int">
+</parameter>
+</method>
+<method name="fromStream"
+ return="android.gesture.LetterRecognizer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="stream" type="java.io.InputStream">
+</parameter>
+</method>
+<method name="fromType"
+ return="android.gesture.LetterRecognizer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+</method>
 <field name="RECOGNIZER_LATIN_LOWERCASE"
  type="int"
  transient="false"
@@ -77087,6 +77474,19 @@
 <parameter name="rssiB" type="int">
 </parameter>
 </method>
+<method name="createMulticastLock"
+ return="android.net.wifi.WifiManager.MulticastLock"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
 <method name="createWifiLock"
  return="android.net.wifi.WifiManager.WifiLock"
  abstract="false"
@@ -77579,6 +77979,48 @@
 >
 </field>
 </class>
+<class name="WifiManager.MulticastLock"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="acquire"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isHeld"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <class name="WifiManager.WifiLock"
  extends="java.lang.Object"
  abstract="false"
@@ -93736,6 +94178,8 @@
 </parameter>
 <parameter name="length" type="int">
 </parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
 </constructor>
 <method name="allowPurging"
  return="boolean"
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 16f0a30..3d3d7d5f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -20,6 +20,7 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.res.Configuration;
@@ -1021,6 +1022,33 @@
             reply.writeStrongBinder(binder);
             return true;
         }
+        
+        case START_BACKUP_AGENT_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data);
+            int backupRestoreMode = data.readInt();
+            boolean success = bindBackupAgent(info, backupRestoreMode);
+            reply.writeNoException();
+            reply.writeInt(success ? 1 : 0);
+            return true;
+        }
+
+        case BACKUP_AGENT_CREATED_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String packageName = data.readString();
+            IBinder agent = data.readStrongBinder();
+            backupAgentCreated(packageName, agent);
+            reply.writeNoException();
+            return true;
+        }
+
+        case UNBIND_BACKUP_AGENT_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data);
+            unbindBackupAgent(info);
+            reply.writeNoException();
+            return true;
+        }
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -1681,6 +1709,43 @@
         return binder;
     }
 
+    public boolean bindBackupAgent(ApplicationInfo app, int backupRestoreMode)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        app.writeToParcel(data, 0);
+        data.writeInt(backupRestoreMode);
+        mRemote.transact(START_BACKUP_AGENT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean success = reply.readInt() != 0;
+        reply.recycle();
+        data.recycle();
+        return success;
+    }
+
+    public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        data.writeStrongBinder(agent);
+        mRemote.transact(BACKUP_AGENT_CREATED_TRANSACTION, data, reply, 0);
+        reply.recycle();
+        data.recycle();
+    }
+
+    public void unbindBackupAgent(ApplicationInfo app) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        app.writeToParcel(data, 0);
+        mRemote.transact(UNBIND_BACKUP_AGENT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+
     public boolean startInstrumentation(ComponentName className, String profileFile,
             int flags, Bundle arguments, IInstrumentationWatcher watcher)
             throws RemoteException {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 06e0a453..29e57cd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -115,6 +115,7 @@
     private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
     private static final boolean DEBUG_BROADCAST = false;
     private static final boolean DEBUG_RESULTS = false;
+    private static final boolean DEBUG_BACKUP = true;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
@@ -499,7 +500,7 @@
             return mResources;
         }
 
-        public Application makeApplication() {
+        public Application makeApplication(boolean forceDefaultAppClass) {
             if (mApplication != null) {
                 return mApplication;
             }
@@ -507,7 +508,7 @@
             Application app = null;
             
             String appClass = mApplicationInfo.className;
-            if (appClass == null) {
+            if (forceDefaultAppClass || (appClass == null)) {
                 appClass = "android.app.Application";
             }
 
@@ -1199,6 +1200,16 @@
         }
     }
 
+    private static final class CreateBackupAgentData {
+        ApplicationInfo appInfo;
+        int backupMode;
+        public String toString() {
+            return "CreateBackupAgentData{appInfo=" + appInfo
+                    + " backupAgent=" + appInfo.backupAgentName
+                    + " mode=" + backupMode + "}";
+        }
+    }
+    
     private static final class CreateServiceData {
         IBinder token;
         ServiceInfo info;
@@ -1239,6 +1250,7 @@
         Bundle instrumentationArgs;
         IInstrumentationWatcher instrumentationWatcher;
         int debugMode;
+        boolean restrictedBackupMode;
         Configuration config;
         boolean handlingProfiling;
         public String toString() {
@@ -1374,6 +1386,21 @@
             queueOrSendMessage(H.RECEIVER, r);
         }
 
+        public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) {
+            CreateBackupAgentData d = new CreateBackupAgentData();
+            d.appInfo = app;
+            d.backupMode = backupMode;
+
+            queueOrSendMessage(H.CREATE_BACKUP_AGENT, d);
+        }
+
+        public final void scheduleDestroyBackupAgent(ApplicationInfo app) {
+            CreateBackupAgentData d = new CreateBackupAgentData();
+            d.appInfo = app;
+
+            queueOrSendMessage(H.DESTROY_BACKUP_AGENT, d);
+        }
+
         public final void scheduleCreateService(IBinder token,
                 ServiceInfo info) {
             CreateServiceData s = new CreateServiceData();
@@ -1419,7 +1446,7 @@
                 ApplicationInfo appInfo, List<ProviderInfo> providers,
                 ComponentName instrumentationName, String profileFile,
                 Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
-                int debugMode, Configuration config,
+                int debugMode, boolean isRestrictedBackupMode, Configuration config,
                 Map<String, IBinder> services) {
             Process.setArgV0(processName);
 
@@ -1437,6 +1464,7 @@
             data.instrumentationArgs = instrumentationArgs;
             data.instrumentationWatcher = instrumentationWatcher;
             data.debugMode = debugMode;
+            data.restrictedBackupMode = isRestrictedBackupMode;
             data.config = config;
             queueOrSendMessage(H.BIND_APPLICATION, data);
         }
@@ -1718,6 +1746,8 @@
         public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
         public static final int RELAUNCH_ACTIVITY       = 126;
         public static final int PROFILER_CONTROL        = 127;
+        public static final int CREATE_BACKUP_AGENT     = 128;
+        public static final int DESTROY_BACKUP_AGENT     = 129;
         String codeToString(int code) {
             if (localLOGV) {
                 switch (code) {
@@ -1749,6 +1779,8 @@
                     case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
                     case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
                     case PROFILER_CONTROL: return "PROFILER_CONTROL";
+                    case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
+                    case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
                 }
             }
             return "(unknown)";
@@ -1851,6 +1883,12 @@
                 case PROFILER_CONTROL:
                     handleProfilerControl(msg.arg1 != 0, (String)msg.obj);
                     break;
+                case CREATE_BACKUP_AGENT:
+                    handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
+                    break;
+                case DESTROY_BACKUP_AGENT:
+                    handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
+                    break;
             }
         }
     }
@@ -1908,6 +1946,8 @@
     Application mInitialApplication;
     final ArrayList<Application> mAllApplications
             = new ArrayList<Application>();
+    // set of instantiated backup agents, keyed by package name
+    final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
     static final ThreadLocal sThreadLocal = new ThreadLocal();
     Instrumentation mInstrumentation;
     String mInstrumentationAppDir = null;
@@ -2269,7 +2309,7 @@
         }
 
         try {
-            Application app = r.packageInfo.makeApplication();
+            Application app = r.packageInfo.makeApplication(false);
             
             if (localLOGV) Log.v(TAG, "Performing launch of " + r);
             if (localLOGV) Log.v(
@@ -2464,7 +2504,7 @@
         }
 
         try {
-            Application app = packageInfo.makeApplication();
+            Application app = packageInfo.makeApplication(false);
             
             if (localLOGV) Log.v(
                 TAG, "Performing receive of " + data.intent
@@ -2507,6 +2547,85 @@
         }
     }
 
+    // Instantiate a BackupAgent and tell it that it's alive
+    private final void handleCreateBackupAgent(CreateBackupAgentData data) {
+        if (DEBUG_BACKUP) Log.v(TAG, "handleCreateBackupAgent: " + data);
+
+        // no longer idle; we have backup work to do
+        unscheduleGcIdler();
+
+        // instantiate the BackupAgent class named in the manifest
+        PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
+        String packageName = packageInfo.mPackageName;
+        if (mBackupAgents.get(packageName) != null) {
+            Log.d(TAG, "BackupAgent " + "  for " + packageName
+                    + " already exists");
+            return;
+        }
+        
+        BackupAgent agent = null;
+        String classname = data.appInfo.backupAgentName;
+        if (classname == null) {
+            if (data.backupMode == IApplicationThread.BACKUP_MODE_INCREMENTAL) {
+                Log.e(TAG, "Attempted incremental backup but no defined agent for "
+                        + packageName);
+                return;
+            }
+            classname = "android.app.FullBackupAgent";
+        }
+        try {
+            java.lang.ClassLoader cl = packageInfo.getClassLoader();
+            agent = (BackupAgent) cl.loadClass(data.appInfo.backupAgentName).newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to instantiate backup agent "
+                    + data.appInfo.backupAgentName + ": " + e.toString(), e);
+        }
+        
+        // set up the agent's context
+        try {
+            if (DEBUG_BACKUP) Log.v(TAG, "Initializing BackupAgent "
+                    + data.appInfo.backupAgentName);
+            
+            ApplicationContext context = new ApplicationContext();
+            context.init(packageInfo, null, this);
+            context.setOuterContext(agent);
+            agent.attach(context);
+            agent.onCreate();
+
+            // tell the OS that we're live now
+            IBinder binder = agent.onBind();
+            try {
+                ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);
+            } catch (RemoteException e) {
+                // nothing to do.
+            }
+            mBackupAgents.put(packageName, agent);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to create BackupAgent "
+                    + data.appInfo.backupAgentName + ": " + e.toString(), e);
+        }
+    }
+
+    // Tear down a BackupAgent
+    private final void handleDestroyBackupAgent(CreateBackupAgentData data) {
+        if (DEBUG_BACKUP) Log.v(TAG, "handleDestroyBackupAgent: " + data);
+        
+        PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
+        String packageName = packageInfo.mPackageName;
+        BackupAgent agent = mBackupAgents.get(packageName);
+        if (agent != null) {
+            try {
+                agent.onDestroy();
+            } catch (Exception e) {
+                Log.w(TAG, "Exception thrown in onDestroy by backup agent of " + data.appInfo);
+                e.printStackTrace();
+            }
+            mBackupAgents.remove(packageName);
+        } else {
+            Log.w(TAG, "Attempt to destroy unknown backup agent " + data);
+        }
+    }
+
     private final void handleCreateService(CreateServiceData data) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
@@ -2532,7 +2651,7 @@
             ApplicationContext context = new ApplicationContext();
             context.init(packageInfo, null, this);
 
-            Application app = packageInfo.makeApplication();
+            Application app = packageInfo.makeApplication(false);
             context.setOuterContext(service);
             service.attach(context, this, data.info.name, data.token, app,
                     ActivityManagerNative.getDefault());
@@ -3694,7 +3813,9 @@
             mInstrumentation = new Instrumentation();
         }
 
-        Application app = data.info.makeApplication();
+        // If the app is being launched for full backup or restore, bring it up in
+        // a restricted environment with the base application class.
+        Application app = data.info.makeApplication(data.restrictedBackupMode);
         mInitialApplication = app;
 
         List<ProviderInfo> providers = data.providers;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index f243185..e28fd0f 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -230,11 +230,13 @@
             IBinder binder = data.readStrongBinder();
             IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder);
             int testMode = data.readInt();
+            boolean restrictedBackupMode = (data.readInt() != 0);
             Configuration config = Configuration.CREATOR.createFromParcel(data);
             HashMap<String, IBinder> services = data.readHashMap(null);
             bindApplication(packageName, info,
                             providers, testName, profileName,
-                            testArgs, testWatcher, testMode, config, services);
+                            testArgs, testWatcher, testMode, restrictedBackupMode,
+                            config, services);
             return true;
         }
         
@@ -339,6 +341,15 @@
             setSchedulingGroup(group);
             return true;
         }
+
+        case SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data);
+            int backupMode = data.readInt();
+            scheduleCreateBackupAgent(appInfo, backupMode);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -492,6 +503,24 @@
         data.recycle();
     }
 
+    public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        app.writeToParcel(data, 0);
+        data.writeInt(backupMode);
+        mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null, 0);
+        data.recycle();
+    }
+
+    public final void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        app.writeToParcel(data, 0);
+        mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null, 0);
+        data.recycle();
+    }
+    
     public final void scheduleCreateService(IBinder token, ServiceInfo info)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -551,7 +580,8 @@
     public final void bindApplication(String packageName, ApplicationInfo info,
             List<ProviderInfo> providers, ComponentName testName,
             String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode,
-            Configuration config, Map<String, IBinder> services) throws RemoteException {
+            boolean restrictedBackupMode, Configuration config,
+            Map<String, IBinder> services) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeString(packageName);
@@ -567,6 +597,7 @@
         data.writeBundle(testArgs);
         data.writeStrongInterface(testWatcher);
         data.writeInt(debugMode);
+        data.writeInt(restrictedBackupMode ? 1 : 0);
         config.writeToParcel(data, 0);
         data.writeMap(services);
         mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
diff --git a/core/java/android/backup/BackupService.java b/core/java/android/app/BackupAgent.java
similarity index 66%
rename from core/java/android/backup/BackupService.java
rename to core/java/android/app/BackupAgent.java
index 50a5921..997bfdc 100644
--- a/core/java/android/backup/BackupService.java
+++ b/core/java/android/app/BackupAgent.java
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package android.backup;
+package android.app;
 
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
-import android.backup.IBackupService;
-import android.content.Intent;
+import android.app.IBackupAgent;
+import android.backup.BackupDataOutput;
+import android.content.Context;
+import android.content.ContextWrapper;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -30,31 +29,18 @@
  * This is the central interface between an application and Android's
  * settings backup mechanism.
  * 
- * In order to use the backup service, your application must implement a
- * subclass of BackupService, and declare an intent filter
- * in the application manifest specifying that your BackupService subclass
- * handles the {@link BackupService#SERVICE_ACTION} intent action.  For example:
- * 
- * <pre class="prettyprint">
- *      &lt;!-- Use the class "MyBackupService" to perform backups for my app --&gt;
- *      &lt;service android:name=".MyBackupService"&gt;
- *          &lt;intent-filter&gt;
- *              &lt;action android:name="android.backup.BackupService.SERVICE" /&gt;
- *          &lt;/intent-filter&gt;
- *      &lt;/service&gt;</pre>
- * 
  * @hide pending API solidification
  */
+public abstract class BackupAgent extends ContextWrapper {
+    public BackupAgent() {
+        super(null);
+    }
 
-public abstract class BackupService extends Service {
-    /**
-     * Service Action: Participate in the backup infrastructure.  Applications
-     * that wish to use the Android backup mechanism must provide an exported
-     * subclass of BackupService and give it an {@link android.content.IntentFilter
-     * IntentFilter} that accepts this action. 
-     */
-    @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_ACTION = "android.backup.BackupService.SERVICE";
+    public void onCreate() {
+    }
+
+    public void onDestroy() {
+    }
 
     /**
      * The application is being asked to write any data changed since the
@@ -91,7 +77,8 @@
      *                 file.  The application should record the final backup state
      *                 here after restoring its data from dataFd.
      */
-    public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data, ParcelFileDescriptor newState);
+    public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data,
+            ParcelFileDescriptor newState);
 
 
     // ----- Core implementation -----
@@ -100,29 +87,33 @@
      * Returns the private interface called by the backup system.  Applications will
      * not typically override this.
      */
-    public IBinder onBind(Intent intent) {
-        if (intent.getAction().equals(SERVICE_ACTION)) {
-            return mBinder;
-        }
-        return null;
+    public IBinder onBind() {
+        return mBinder;
     }
 
     private final IBinder mBinder = new BackupServiceBinder().asBinder();
 
+    /** @hide */
+    public void attach(Context context) {
+        attachBaseContext(context);
+    }
+
     // ----- IBackupService binder interface -----
-    private class BackupServiceBinder extends IBackupService.Stub {
+    private class BackupServiceBinder extends IBackupAgent.Stub {
+        private static final String TAG = "BackupServiceBinder";
+
         public void doBackup(ParcelFileDescriptor oldState,
                 ParcelFileDescriptor data,
                 ParcelFileDescriptor newState) throws RemoteException {
             // !!! TODO - real implementation; for now just invoke the callbacks directly
-            Log.v("BackupServiceBinder", "doBackup() invoked");
-            BackupDataOutput output = new BackupDataOutput(BackupService.this,
+            Log.v(TAG, "doBackup() invoked");
+            BackupDataOutput output = new BackupDataOutput(BackupAgent.this,
                     data.getFileDescriptor());
             try {
-                BackupService.this.onBackup(oldState, output, newState);
+                BackupAgent.this.onBackup(oldState, output, newState);
             } catch (RuntimeException ex) {
-                Log.d("BackupService", "onBackup ("
-                        + BackupService.this.getClass().getName() + ") threw", ex);
+                Log.d("BackupAgent", "onBackup ("
+                        + BackupAgent.this.getClass().getName() + ") threw", ex);
                 throw ex;
             }
         }
@@ -130,8 +121,8 @@
         public void doRestore(ParcelFileDescriptor data,
                 ParcelFileDescriptor newState) throws RemoteException {
             // !!! TODO - real implementation; for now just invoke the callbacks directly
-            Log.v("BackupServiceBinder", "doRestore() invoked");
-            BackupService.this.onRestore(data, newState);
+            Log.v(TAG, "doRestore() invoked");
+            BackupAgent.this.onRestore(data, newState);
         }
     }
 }
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java
new file mode 100644
index 0000000..18d62e3
--- /dev/null
+++ b/core/java/android/app/FullBackupAgent.java
@@ -0,0 +1,58 @@
+package android.app;
+
+import android.backup.BackupDataOutput;
+import android.backup.FileBackupHelper;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+/**
+ * Backs up an application's entire /data/data/&lt;package&gt;/... file system.  This
+ * class is used by the desktop full backup mechanism and is not intended for direct
+ * use by applications.
+ * 
+ * {@hide}
+ */
+
+public class FullBackupAgent extends BackupAgent {
+    // !!! TODO: turn off debugging
+    private static final String TAG = "FullBackupAgent";
+    private static final boolean DEBUG = true;
+
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) {
+        LinkedList<File> dirsToScan = new LinkedList<File>();
+        ArrayList<String> allFiles = new ArrayList<String>();
+
+        // build the list of files in the app's /data/data tree
+        dirsToScan.add(getFilesDir());
+        if (DEBUG) Log.v(TAG, "Backing up dir tree @ " + getFilesDir().getAbsolutePath() + " :");
+        while (dirsToScan.size() > 0) {
+            File dir = dirsToScan.removeFirst();
+            File[] contents = dir.listFiles();
+            if (contents != null) {
+                for (File f : contents) {
+                    if (f.isDirectory()) {
+                        dirsToScan.add(f);
+                    } else if (f.isFile()) {
+                        if (DEBUG) Log.v(TAG, "    " + f.getAbsolutePath());
+                        allFiles.add(f.getAbsolutePath());
+                    }
+                }
+            }
+        }
+
+        // That's the file set; now back it all up
+        FileBackupHelper.performBackup(this, oldState, data, newState,
+                (String[]) allFiles.toArray());
+    }
+
+    @Override
+    public void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) {
+    }
+
+}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index d15a154..c948aec 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -21,6 +21,7 @@
 import android.content.IContentProvider;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.ProviderInfo;
@@ -149,6 +150,11 @@
     public void serviceDoneExecuting(IBinder token) throws RemoteException;
     public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
     
+    public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
+            throws RemoteException;
+    public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
+    public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;
+    
     public boolean startInstrumentation(ComponentName className, String profileFile,
             int flags, Bundle arguments, IInstrumentationWatcher watcher)
             throws RemoteException;
@@ -397,4 +403,7 @@
     int SHUTDOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+86;
     int STOP_APP_SWITCHES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+87;
     int RESUME_APP_SWITCHES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+88;
+    int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
+    int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
+    int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index ec03d3a..bca1fea 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -59,6 +59,11 @@
             int configChanges) throws RemoteException;
     void scheduleReceiver(Intent intent, ActivityInfo info, int resultCode,
             String data, Bundle extras, boolean sync) throws RemoteException;
+    static final int BACKUP_MODE_INCREMENTAL = 0;
+    static final int BACKUP_MODE_FULL = 1;
+    static final int BACKUP_MODE_RESTORE = 2;
+    void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) throws RemoteException;
+    void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException;
     void scheduleCreateService(IBinder token, ServiceInfo info) throws RemoteException;
     void scheduleBindService(IBinder token,
             Intent intent, boolean rebind) throws RemoteException;
@@ -71,8 +76,8 @@
     static final int DEBUG_WAIT = 2;
     void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
             ComponentName testName, String profileName, Bundle testArguments, 
-            IInstrumentationWatcher testWatcher, int debugMode, Configuration config, Map<String,
-            IBinder> services) throws RemoteException;
+            IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode,
+            Configuration config, Map<String, IBinder> services) throws RemoteException;
     void scheduleExit() throws RemoteException;
     void requestThumbnail(IBinder token) throws RemoteException;
     void scheduleConfigurationChanged(Configuration config) throws RemoteException;
@@ -119,4 +124,6 @@
     int REQUEST_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
     int PROFILER_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
     int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
+    int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
+    int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
 }
diff --git a/core/java/android/backup/IBackupService.aidl b/core/java/android/app/IBackupAgent.aidl
similarity index 94%
rename from core/java/android/backup/IBackupService.aidl
rename to core/java/android/app/IBackupAgent.aidl
index 1bde8ea..bb9f008 100644
--- a/core/java/android/backup/IBackupService.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package android.backup;
+package android.app;
 
 import android.os.ParcelFileDescriptor;
  
 /**
  * Interface presented by applications being asked to participate in the
  * backup & restore mechanism.  End user code does not typically implement
- * this interface; they subclass BackupService instead.
+ * this interface; they subclass BackupAgent instead.
  *
  * {@hide}
  */ 
-interface IBackupService {
+interface IBackupAgent {
     /**
      * Request that the app perform an incremental backup.
      *
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index ff110c8..bcb2791 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1174,7 +1174,7 @@
      */
     protected void launchQuerySearch(int actionKey, String actionMsg)  {
         String query = mSearchAutoComplete.getText().toString();
-        Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null, 
+        Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null,
                 actionKey, actionMsg);
         launchIntent(intent);
     }
@@ -1202,13 +1202,26 @@
     protected boolean launchSuggestion(int position, int actionKey, String actionMsg) {
         Cursor c = mSuggestionsAdapter.getCursor();
         if ((c != null) && c.moveToPosition(position)) {
+            // let the cursor know which position was clicked
+            final Bundle clickResponse = new Bundle(1);
+            clickResponse.putInt(SearchManager.RESPOND_EXTRA_POSITION_CLICKED, position);
+            final Bundle response = c.respond(clickResponse);
+
+            // the convention is to send a position to select in response to a click (if applicable)
+            final int posToSelect = response.getInt(
+                    SearchManager.RESPOND_EXTRA_POSITION_SELECTED,
+                    SuggestionsAdapter.NO_ITEM_TO_SELECT);
+            mSuggestionsAdapter.setListItemToSelect(posToSelect);            
+
+            // launch the intent
             Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
             launchIntent(intent);
+
             return true;
         }
         return false;
     }
-    
+
     /**
      * Launches an intent. Also dismisses the search dialog if not in global search mode.
      */
@@ -1235,9 +1248,6 @@
         if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) {
             handleChangeSourceIntent(intent);
             return true;
-        } else if (SearchManager.INTENT_ACTION_CURSOR_RESPOND.equals(action)) {
-            handleCursorRespondIntent(intent);
-            return true;
         }
         return false;
     }
@@ -1268,17 +1278,14 @@
         String query = intent.getStringExtra(SearchManager.QUERY);
         setUserQuery(query);
     }
-    
+
     /**
-     * Handles {@link SearchManager#INTENT_ACTION_CURSOR_RESPOND}.
+     * Sets the list item selection in the AutoCompleteTextView's ListView.
      */
-    private void handleCursorRespondIntent(Intent intent) {
-        Cursor c = mSuggestionsAdapter.getCursor();
-        if (c != null) {
-            c.respond(intent.getExtras());
-        }
+    public void setListSelection(int index) {
+        mSearchAutoComplete.setListSelection(index);
     }
-    
+
     /**
      * Saves the previous component that was searched, so that we can go
      * back to it.
@@ -1348,6 +1355,12 @@
         try {
             // use specific action if supplied, or default action if supplied, or fixed default
             String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
+
+            // some items are display only, or have effect via the cursor respond click reporting.
+            if (SearchManager.INTENT_ACTION_NONE.equals(action)) {
+                return null;
+            }
+
             if (action == null) {
                 action = mSearchable.getSuggestIntentAction();
             }
@@ -1370,7 +1383,7 @@
             Uri dataUri = (data == null) ? null : Uri.parse(data);
 
             String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
-            
+
             String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
 
             return createIntent(action, dataUri, query, extraData, actionKey, actionMsg);
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3bf37c3..b4a3a78 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1148,7 +1148,7 @@
      * @hide
      */
     public final static String SOURCE = "source";
-    
+
     /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
@@ -1162,10 +1162,44 @@
     /**
      * Intent extra data key: This key will be used for the extra populated by the
      * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
+     *
      * {@hide}
      */
     public final static String EXTRA_DATA_KEY = "intent_extra_data_key";
-    
+
+
+    /**
+     * Used by the search dialog to ask the global search provider whether there are any pending
+     * sources that have yet to respond.  Specifically, the search dialog will call
+     * {@link Cursor#respond} with a bundle containing this extra as a key, and expect the same key
+     * to be in the response, with a boolean value indicating whether there are pending sources.
+     *
+     * {@hide}
+     */
+    public final static String RESPOND_EXTRA_PENDING_SOURCES = "respond_extra_pending_sources";
+
+    /**
+     * Used by the search dialog to tell the cursor that supplied suggestions which item was clicked
+     * before launching the intent.  The search dialog will call {@link Cursor#respond} with a
+     * bundle containing this extra as a key and the position that was clicked as the value.
+     *
+     * The response bundle will use {@link #RESPOND_EXTRA_POSITION_SELECTED} to return an int value
+     * of the index that should be selected, if applicable.
+     *
+     * {@hide}
+     */
+    public final static String RESPOND_EXTRA_POSITION_CLICKED = "respond_extra_position_clicked";
+
+    /**
+     * Used as a key in the response bundle from a call to {@link Cursor#respond} that sends the
+     * position that is clicked.
+     *
+     * @see #RESPOND_EXTRA_POSITION_CLICKED
+     *
+     * {@hide}
+     */
+    public final static String RESPOND_EXTRA_POSITION_SELECTED = "respond_extra_position_selected";
+
     /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
@@ -1302,9 +1336,10 @@
     /**
      * Column name for suggestions cursor.  <i>Optional.</i>  This column allows suggestions
      *  to provide additional arbitrary data which will be included as an extra under the key
-     *  {@link #EXTRA_DATA_KEY}.
-     * 
-     * @hide pending API council approval
+     *  {@link #EXTRA_DATA_KEY}. For use by the global search system only - if other providers
+     *  attempt to use this column, the value will be overwritten by global search.
+     *
+     * @hide
      */
     public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
     /**
@@ -1362,21 +1397,7 @@
      */
     public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE 
             = "android.search.action.CHANGE_SEARCH_SOURCE";
-    
-    /**
-     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
-     * the search dialog will call {@link Cursor#respond(Bundle)} when the
-     * suggestion is clicked. 
-     * 
-     * The {@link Bundle} argument will be constructed
-     * in the same way as the "extra" bundle included in an Intent constructed 
-     * from the suggestion.
-     * 
-     * @hide Pending API council approval.
-     */
-    public final static String INTENT_ACTION_CURSOR_RESPOND
-            = "android.search.action.CURSOR_RESPOND";
-    
+
     /**
      * Intent action for finding the global search activity.
      * The global search provider should handle this intent.
@@ -1394,6 +1415,14 @@
      */
     public final static String INTENT_ACTION_SEARCH_SETTINGS 
             = "android.search.action.SEARCH_SETTINGS";
+
+    /**
+     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
+     * the search dialog will take no action.
+     *
+     * @hide
+     */
+    public final static String INTENT_ACTION_NONE = "android.search.action.ZILCH";
     
     /**
      * Reference to the shared system search service.
@@ -1505,25 +1534,27 @@
     }
     
     /**
-     * See {@link #setOnDismissListener} for configuring your activity to monitor search UI state.
+     * See {@link SearchManager#setOnDismissListener} for configuring your activity to monitor
+     * search UI state.
      */
     public interface OnDismissListener {
         /**
-         * This method will be called when the search UI is dismissed. To make use if it, you must
-         * implement this method in your activity, and call {@link #setOnDismissListener} to 
-         * register it.
+         * This method will be called when the search UI is dismissed. To make use of it, you must
+         * implement this method in your activity, and call
+         * {@link SearchManager#setOnDismissListener} to register it.
          */
         public void onDismiss();
     }
     
     /**
-     * See {@link #setOnCancelListener} for configuring your activity to monitor search UI state.
+     * See {@link SearchManager#setOnCancelListener} for configuring your activity to monitor
+     * search UI state.
      */
     public interface OnCancelListener {
         /**
          * This method will be called when the search UI is canceled. To make use if it, you must
-         * implement this method in your activity, and call {@link #setOnCancelListener} to 
-         * register it.
+         * implement this method in your activity, and call
+         * {@link SearchManager#setOnCancelListener} to register it.
          */
         public void onCancel();
     }
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index aeb96b4..451697a 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -50,6 +50,11 @@
     // so we can correctly display (or not display) the 'working' spinner in the search dialog.
     public static final String IS_WORKING = "isWorking";
     
+    // The value used to tell a cursor to display the corpus selectors, if this is global
+    // search. Also returns the index of the more results item to allow the SearchDialog
+    // to tell the ListView to scroll to that list item.
+    public static final String SHOW_CORPUS_SELECTORS = "showCorpusSelectors";
+    
     private static final boolean DBG = false;
     private static final String LOG_TAG = "SuggestionsAdapter";
     
@@ -67,7 +72,16 @@
     private int mIconName2Col;
     private int mIconBitmap1Col;
     private int mIconBitmap2Col;
-    
+
+    // This value is stored in SuggestionsAdapter by the SearchDialog to indicate whether
+    // a particular list item should be selected upon the next call to notifyDataSetChanged.
+    // This is used to indicate the index of the "More results..." list item so that when
+    // the data set changes after a click of "More results...", we can correctly tell the
+    // ListView to scroll to the right line item. It gets reset to NO_ITEM_TO_SELECT every time it
+    // is consumed.
+    private int mListItemToSelect = NO_ITEM_TO_SELECT;
+    static final int NO_ITEM_TO_SELECT = -1;
+
     public SuggestionsAdapter(Context context, SearchDialog searchDialog, SearchableInfo searchable,
             WeakHashMap<String, Drawable> outsideDrawablesCache, boolean globalSearchMode) {
         super(context,
@@ -134,6 +148,19 @@
     public void notifyDataSetChanged() {
         super.notifyDataSetChanged();
         updateWorking();
+        if (mListItemToSelect != NO_ITEM_TO_SELECT) {
+            mSearchDialog.setListSelection(mListItemToSelect);
+            mListItemToSelect = NO_ITEM_TO_SELECT;
+        }
+    }
+    
+    /**
+     * Specifies the list item to select upon next call of {@link #notifyDataSetChanged()},
+     * in order to let us scroll the "More results..." list item to the top of the screen
+     * (or as close as it can get) when clicked.
+     */
+    public void setListItemToSelect(int index) {
+        mListItemToSelect = index;
     }
     
     /**
@@ -143,14 +170,12 @@
         if (!mGlobalSearchMode || mCursor == null) return;
         
         Bundle request = new Bundle();
-        request.putString(SearchManager.EXTRA_DATA_KEY, IS_WORKING);
+        request.putString(SearchManager.RESPOND_EXTRA_PENDING_SOURCES, "DUMMY");
         Bundle response = mCursor.respond(request);
-        if (response.containsKey(IS_WORKING)) {
-            boolean isWorking = response.getBoolean(IS_WORKING);
-            mSearchDialog.setWorking(isWorking);
-        }
+
+        mSearchDialog.setWorking(response.getBoolean(SearchManager.RESPOND_EXTRA_PENDING_SOURCES));
     }
-    
+
     /**
      * Tags the view with cached child view look-ups.
      */
@@ -336,12 +361,16 @@
         
         // First, check the cache.
         Drawable drawable = mOutsideDrawablesCache.get(drawableId);
-        if (drawable != null) return drawable;
+        if (drawable != null) {
+            if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + drawableId);
+            return drawable;
+        }
 
         try {
             // Not cached, try using it as a plain resource ID in the provider's context.
             int resourceId = Integer.parseInt(drawableId);
             drawable = mProviderContext.getResources().getDrawable(resourceId);
+            if (DBG) Log.d(LOG_TAG, "Found icon by resource ID: " + drawableId);
         } catch (NumberFormatException nfe) {
             // The id was not an integer resource id.
             // Let the ContentResolver handle content, android.resource and file URIs.
@@ -350,7 +379,9 @@
                 drawable = Drawable.createFromStream(
                         mProviderContext.getContentResolver().openInputStream(uri),
                         null);
+                if (DBG) Log.d(LOG_TAG, "Opened icon input stream: " + drawableId);
             } catch (FileNotFoundException fnfe) {
+                if (DBG) Log.d(LOG_TAG, "Icon stream not found: " + drawableId);
                 // drawable = null;
             }
                     
@@ -360,7 +391,7 @@
                 mOutsideDrawablesCache.put(drawableId, drawable);
             }
         } catch (NotFoundException nfe) {
-            // Resource could not be found
+            if (DBG) Log.d(LOG_TAG, "Icon resource not found: " + drawableId);
             // drawable = null;
         }
         
@@ -377,7 +408,7 @@
      */
     public static String getColumnString(Cursor cursor, String columnName) {
         int col = cursor.getColumnIndex(columnName);
-        if (col == -1) {
+        if (col == NO_ITEM_TO_SELECT) {
             return null;
         }
         return cursor.getString(col);
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index cf22798..3468d70 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -34,8 +34,22 @@
     oneway void dataChanged(String packageName);
 
     /**
+     * Notifies the Backup Manager Service that an agent has become available.  This
+     * method is only invoked by the Activity Manager.
+     * !!! TODO: permission
+     */
+    oneway void agentConnected(String packageName, IBinder agent);
+
+    /**
+     * Notify the Backup Manager Service that an agent has unexpectedly gone away.
+     * This method is only invoked by the Activity Manager.
+     * !!! TODO: permission
+     */
+    oneway void agentDisconnected(String packageName);
+
+    /**
      * Schedule a full backup of the given package.
-     * !!! TODO: protect with a signature-or-system permission?
+     * !!! TODO: permission
      */
     oneway void scheduleFullBackup(String packageName);
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ad022e7..f16eb74 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -58,11 +58,22 @@
      * Class implementing the Application's manage space
      * functionality.  From the "manageSpaceActivity"
      * attribute. This is an optional attribute and will be null if
-     * application's dont specify it in their manifest
+     * applications don't specify it in their manifest
      */
     public String manageSpaceActivityName;    
     
     /**
+     * Class implementing the Application's backup functionality.  From
+     * the "backupAgent" attribute.  This is an optional attribute and
+     * will be null if the application does not specify it in its manifest.
+     * 
+     * <p>If android:allowBackup is set to false, this attribute is ignored.
+     * 
+     * {@hide}
+     */
+    public String backupAgentName;
+    
+    /**
      * Value for {@link #flags}: if set, this application is installed in the
      * device's system image.
      */
@@ -93,7 +104,7 @@
     public static final int FLAG_PERSISTENT = 1<<3;
 
     /**
-     * Value for {@link #flags}: set to true iif this application holds the
+     * Value for {@link #flags}: set to true if this application holds the
      * {@link android.Manifest.permission#FACTORY_TEST} permission and the
      * device is running in factory test mode.
      */
@@ -126,6 +137,14 @@
     public static final int FLAG_TEST_ONLY = 1<<8;
 
     /**
+     * Value for {@link #flags}: this is false if the application has set
+     * its android:allowBackup to false, true otherwise.
+     * 
+     * {@hide}
+     */
+    public static final int FLAG_ALLOW_BACKUP = 1<<10;
+    
+    /**
      * Flags associated with the application.  Any combination of
      * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
@@ -285,6 +304,7 @@
         dest.writeInt(targetSdkVersion);
         dest.writeInt(enabled ? 1 : 0);
         dest.writeString(manageSpaceActivityName);
+        dest.writeString(backupAgentName);
         dest.writeInt(descriptionRes);
         dest.writeIntArray(supportsDensities);
     }
@@ -315,6 +335,7 @@
         targetSdkVersion = source.readInt();
         enabled = source.readInt() != 0;
         manageSpaceActivityName = source.readString();
+        backupAgentName = source.readString();
         descriptionRes = source.readInt();
         supportsDensities = source.createIntArray();
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 78462f1..212b590 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -74,10 +74,12 @@
      * added to older SDKs appearing before those added to newer SDKs.
      * @hide
      */
-    public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = new PackageParser.NewPermissionInfo[] {
-        new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_SDCARD,
-                android.os.Build.VERSION_CODES.DONUT,
-                0)
+    public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
+        new PackageParser.NewPermissionInfo[] {
+            new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                    android.os.Build.VERSION_CODES.DONUT, 0),
+            new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
+                    android.os.Build.VERSION_CODES.DONUT, 0)
     };
 
     private String mArchiveSourcePath;
@@ -1174,6 +1176,19 @@
                     outError);
         }
 
+        boolean allowBackup = sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
+        if (allowBackup) {
+            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
+            String backupAgent = sa.getNonResourceString(
+                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent);
+            if (backupAgent != null) {
+                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
+                Log.v(TAG, "android:backupAgent = " + ai.backupAgentName
+                        + " from " + pkgName + "+" + backupAgent);
+            }
+        }
+        
         TypedValue v = sa.peekValue(
                 com.android.internal.R.styleable.AndroidManifestApplication_label);
         if (v != null && (ai.labelRes=v.resourceId) == 0) {
diff --git a/core/java/android/gesture/Gesture.java b/core/java/android/gesture/Gesture.java
index 6aca105..8e71c57 100755
--- a/core/java/android/gesture/Gesture.java
+++ b/core/java/android/gesture/Gesture.java
@@ -46,7 +46,7 @@
 
     private static int sGestureCount = 0;
 
-    private RectF mBoundingBox;
+    private final RectF mBoundingBox = new RectF();
 
     // the same as its instance ID
     private long mGestureID;
@@ -83,12 +83,7 @@
      */
     public void addStroke(GestureStroke stroke) {
         mStrokes.add(stroke);
-
-        if (mBoundingBox == null) {
-            mBoundingBox = new RectF(stroke.boundingBox);
-        } else {
-            mBoundingBox.union(stroke.boundingBox);
-        }
+        mBoundingBox.union(stroke.boundingBox);
     }
 
     /**
diff --git a/core/java/android/gesture/GestureLibraries.java b/core/java/android/gesture/GestureLibraries.java
new file mode 100644
index 0000000..2ce7a8e
--- /dev/null
+++ b/core/java/android/gesture/GestureLibraries.java
@@ -0,0 +1,139 @@
+/*
+ * 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.gesture;
+
+import android.util.Log;
+import static android.gesture.GestureConstants.*;
+import android.content.Context;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+
+public final class GestureLibraries {
+    private GestureLibraries() {
+    }
+
+    public static GestureLibrary fromFile(String path) {
+        return fromFile(new File(path));
+    }
+
+    public static GestureLibrary fromFile(File path) {
+        return new FileGestureLibrary(path);
+    }
+
+    public static GestureLibrary fromPrivateFile(Context context, String name) {
+        return fromFile(context.getFileStreamPath(name));
+    }
+
+    public static GestureLibrary fromRawResource(Context context, int resourceId) {
+        return new ResourceGestureLibrary(context, resourceId);
+    }
+
+    private static class FileGestureLibrary extends GestureLibrary {
+        private final File mPath;
+
+        public FileGestureLibrary(File path) {
+            mPath = path;
+        }
+
+        @Override
+        public boolean isReadOnly() {
+            return !mPath.canWrite();
+        }
+
+        public boolean save() {
+            final File file = mPath;
+            if (!file.canWrite()) return false;
+
+            if (!file.getParentFile().exists()) {
+                if (!file.getParentFile().mkdirs()) {
+                    return false;
+                }
+            }
+
+            boolean result = false;
+            try {
+                mStore.save(new FileOutputStream(file), true);
+                result = true;
+            } catch (FileNotFoundException e) {
+                Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);
+            } catch (IOException e) {
+                Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);
+            }
+
+            return result;
+        }
+
+        public boolean load() {
+            boolean result = false;
+            final File file = mPath;
+            if (file.exists() && file.canRead()) {
+                try {
+                    mStore.load(new FileInputStream(file), true);
+                    result = true;
+                } catch (FileNotFoundException e) {
+                    Log.d(LOG_TAG, "Could not load the gesture library from " + mPath, e);
+                } catch (IOException e) {
+                    Log.d(LOG_TAG, "Could not load the gesture library from " + mPath, e);
+                }
+            }
+
+            return result;
+        }
+    }
+
+    private static class ResourceGestureLibrary extends GestureLibrary {
+        private final WeakReference<Context> mContext;
+        private final int mResourceId;
+
+        public ResourceGestureLibrary(Context context, int resourceId) {
+            mContext = new WeakReference<Context>(context);
+            mResourceId = resourceId;
+        }
+
+        @Override
+        public boolean isReadOnly() {
+            return true;
+        }
+
+        public boolean save() {
+            return false;
+        }
+
+        public boolean load() {
+            boolean result = false;
+            final Context context = mContext.get();
+            if (context != null) {
+                final InputStream in = context.getResources().openRawResource(mResourceId);
+                try {
+                    mStore.load(in, true);
+                    result = true;
+                } catch (IOException e) {
+                    Log.d(LOG_TAG, "Could not load the gesture library from raw resource " +
+                            context.getResources().getResourceName(mResourceId), e);
+                }
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/core/java/android/gesture/GestureLibrary.java b/core/java/android/gesture/GestureLibrary.java
index 1cf192e..a29c2c8 100644
--- a/core/java/android/gesture/GestureLibrary.java
+++ b/core/java/android/gesture/GestureLibrary.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2009 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.
@@ -14,333 +14,68 @@
  * limitations under the License.
  */
 
+
 package android.gesture;
 
-import android.util.Log;
-import android.os.SystemClock;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.DataOutputStream;
-import java.io.DataInputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Set;
-import java.util.Map;
+import java.util.ArrayList;
 
-import static android.gesture.GestureConstants.LOG_TAG;
+public abstract class GestureLibrary {
+    protected final GestureStore mStore;
 
-/**
- * GestureLibrary maintains gesture examples and makes predictions on a new
- * gesture
- */
-//
-//    File format for GestureLibrary:
-//
-//                Nb. bytes   Java type   Description
-//                -----------------------------------
-//    Header
-//                2 bytes     short       File format version number
-//                4 bytes     int         Number of entries
-//    Entry
-//                X bytes     UTF String  Entry name
-//                4 bytes     int         Number of gestures
-//    Gesture
-//                8 bytes     long        Gesture ID
-//                4 bytes     int         Number of strokes
-//    Stroke
-//                4 bytes     int         Number of points
-//    Point
-//                4 bytes     float       X coordinate of the point
-//                4 bytes     float       Y coordinate of the point
-//                8 bytes     long        Time stamp
-//
-public class GestureLibrary {
-    public static final int SEQUENCE_INVARIANT = 1;
-    // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed
-    public static final int SEQUENCE_SENSITIVE = 2;
-
-    // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
-    public static final int ORIENTATION_INVARIANT = 1;
-    public static final int ORIENTATION_SENSITIVE = 2;
-
-    private static final short FILE_FORMAT_VERSION = 1;
-
-    private static final boolean PROFILE_LOADING_SAVING = false;
-
-    private int mSequenceType = SEQUENCE_SENSITIVE;
-    private int mOrientationStyle = ORIENTATION_SENSITIVE;
-
-    private final String mGestureFileName;
-
-    private final HashMap<String, ArrayList<Gesture>> mNamedGestures =
-            new HashMap<String, ArrayList<Gesture>>();
-
-    private Learner mClassifier;
-
-    private boolean mChanged = false;
-
-    /**
-     * @param path where gesture data is stored
-     */
-    public GestureLibrary(String path) {
-        mGestureFileName = path;
-        mClassifier = new InstanceLearner();
+    protected GestureLibrary() {
+        mStore = new GestureStore();
     }
 
-    /**
-     * Specify how the gesture library will handle orientation. 
-     * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
-     * 
-     * @param style
-     */
+    public abstract boolean save();
+
+    public abstract boolean load();
+
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    public Learner getLearner() {
+        return mStore.getLearner();
+    }
+
     public void setOrientationStyle(int style) {
-        mOrientationStyle = style;
+        mStore.setOrientationStyle(style);
     }
 
     public int getOrientationStyle() {
-        return mOrientationStyle;
+        return mStore.getOrientationStyle();
     }
 
-    /**
-     * @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
-     */
     public void setSequenceType(int type) {
-        mSequenceType = type;
+        mStore.setSequenceType(type);
     }
 
-    /**
-     * @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
-     */
     public int getSequenceType() {
-        return mSequenceType;
+        return mStore.getSequenceType();
     }
 
-    /**
-     * Get all the gesture entry names in the library
-     * 
-     * @return a set of strings
-     */
     public Set<String> getGestureEntries() {
-        return mNamedGestures.keySet();
+        return mStore.getGestureEntries();
     }
 
-    /**
-     * Recognize a gesture
-     * 
-     * @param gesture the query
-     * @return a list of predictions of possible entries for a given gesture
-     */
     public ArrayList<Prediction> recognize(Gesture gesture) {
-        Instance instance = Instance.createInstance(mSequenceType, gesture, null);
-        return mClassifier.classify(mSequenceType, instance.vector);
+        return mStore.recognize(gesture);
     }
 
-    /**
-     * Add a gesture for the entry
-     * 
-     * @param entryName entry name
-     * @param gesture
-     */
     public void addGesture(String entryName, Gesture gesture) {
-        if (entryName == null || entryName.length() == 0) {
-            return;
-        }
-        ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
-        if (gestures == null) {
-            gestures = new ArrayList<Gesture>();
-            mNamedGestures.put(entryName, gestures);
-        }
-        gestures.add(gesture);
-        mClassifier.addInstance(Instance.createInstance(mSequenceType, gesture, entryName));
-        mChanged = true;
+        mStore.addGesture(entryName, gesture);
     }
 
-    /**
-     * Remove a gesture from the library. If there are no more gestures for the
-     * given entry, the gesture entry will be removed.
-     * 
-     * @param entryName entry name
-     * @param gesture
-     */
     public void removeGesture(String entryName, Gesture gesture) {
-        ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
-        if (gestures == null) {
-            return;
-        }
-
-        gestures.remove(gesture);
-
-        // if there are no more samples, remove the entry automatically
-        if (gestures.isEmpty()) {
-            mNamedGestures.remove(entryName);
-        }
-
-        mClassifier.removeInstance(gesture.getID());
-
-        mChanged = true;
+        mStore.removeGesture(entryName, gesture);
     }
 
-    /**
-     * Remove a entry of gestures
-     * 
-     * @param entryName the entry name
-     */
     public void removeEntry(String entryName) {
-        mNamedGestures.remove(entryName);
-        mClassifier.removeInstances(entryName);
-        mChanged = true;
+        mStore.removeEntry(entryName);
     }
 
-    /**
-     * Get all the gestures of an entry
-     * 
-     * @param entryName
-     * @return the list of gestures that is under this name
-     */
     public ArrayList<Gesture> getGestures(String entryName) {
-        ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
-        if (gestures != null) {
-            return new ArrayList<Gesture>(gestures);
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Save the gesture library
-     */
-    public boolean save() {
-        if (!mChanged) {
-            return true;
-        }
-
-        boolean result = false;
-        DataOutputStream out = null;
-
-        try {
-            File file = new File(mGestureFileName);
-            if (!file.getParentFile().exists()) {
-                if (!file.getParentFile().mkdirs()) {
-                    return false;
-                }
-            }
-
-            long start;
-            if (PROFILE_LOADING_SAVING) {
-                start = SystemClock.elapsedRealtime();
-            }
-
-            final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures;
-
-            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file),
-                    GestureConstants.IO_BUFFER_SIZE));
-            // Write version number
-            out.writeShort(FILE_FORMAT_VERSION);
-            // Write number of entries
-            out.writeInt(maps.size());
-
-            for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) {
-                final String key = entry.getKey();
-                final ArrayList<Gesture> examples = entry.getValue();
-                final int count = examples.size();
-
-                // Write entry name
-                out.writeUTF(key);
-                // Write number of examples for this entry
-                out.writeInt(count);
-
-                for (int i = 0; i < count; i++) {
-                    examples.get(i).serialize(out);
-                }
-            }
-
-            out.flush();
-
-            if (PROFILE_LOADING_SAVING) {
-                long end = SystemClock.elapsedRealtime();
-                Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms");
-            }
-
-            mChanged = false;
-            result = true;
-        } catch (IOException ex) {
-            Log.d(LOG_TAG, "Failed to save gestures:", ex);
-        } finally {
-            GestureUtilities.closeStream(out);
-        }
-
-        return result;
-    }
-
-    /**
-     * Load the gesture library
-     */
-    public boolean load() {
-        boolean result = false;
-
-        final File file = new File(mGestureFileName);
-        if (file.exists()) {
-            DataInputStream in = null;
-            try {
-                in = new DataInputStream(new BufferedInputStream(
-                        new FileInputStream(mGestureFileName), GestureConstants.IO_BUFFER_SIZE));
-
-                long start;
-                if (PROFILE_LOADING_SAVING) {
-                    start = SystemClock.elapsedRealtime();
-                }
-
-                // Read file format version number
-                final short versionNumber = in.readShort();
-                switch (versionNumber) {
-                    case 1:
-                        readFormatV1(in);
-                        break;
-                }
-
-                if (PROFILE_LOADING_SAVING) {
-                    long end = SystemClock.elapsedRealtime();
-                    Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms");
-                }
-
-                result = true;
-            } catch (IOException ex) {
-                Log.d(LOG_TAG, "Failed to load gestures:", ex);
-            } finally {
-                GestureUtilities.closeStream(in);
-            }
-        }
-
-        return result;
-    }
-
-    private void readFormatV1(DataInputStream in) throws IOException {
-        final Learner classifier = mClassifier;
-        final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures;
-        namedGestures.clear();
-
-        // Number of entries in the library
-        final int entriesCount = in.readInt();
-
-        for (int i = 0; i < entriesCount; i++) {
-            // Entry name
-            final String name = in.readUTF();
-            // Number of gestures
-            final int gestureCount = in.readInt();
-
-            final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount);
-            for (int j = 0; j < gestureCount; j++) {
-                final Gesture gesture = Gesture.deserialize(in);
-                gestures.add(gesture);
-                classifier.addInstance(Instance.createInstance(mSequenceType, gesture, name));
-            }
-
-            namedGestures.put(name, gestures);
-        }
+        return mStore.getGestures(entryName);
     }
 }
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index c21cc55..227cf3d 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -45,8 +45,9 @@
  * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeAngleThreshold
  * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeLengthThreshold
  * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeSquarenessThreshold
- * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeType 
+ * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeType
  * @attr ref android.R.styleable#GestureOverlayView_gestureColor
+ * @attr ref android.R.styleable#GestureOverlayView_orientation
  * @attr ref android.R.styleable#GestureOverlayView_uncertainGestureColor
  */
 public class GestureOverlayView extends FrameLayout {
@@ -75,7 +76,7 @@
     private int mInvalidateExtraBorder = 10;
 
     private int mGestureStrokeType = GESTURE_STROKE_TYPE_SINGLE;
-    private float mGestureStrokeLengthThreshold = 30.0f;
+    private float mGestureStrokeLengthThreshold = 50.0f;
     private float mGestureStrokeSquarenessTreshold = 0.275f;
     private float mGestureStrokeAngleThreshold = 40.0f;
 
@@ -86,7 +87,7 @@
 
     private float mX;
     private float mY;
-    
+
     private float mCurveEndX;
     private float mCurveEndY;
 
@@ -516,12 +517,12 @@
         final int count = listeners.size();
         for (int i = 0; i < count; i++) {
             listeners.get(i).onGestureStarted(this, event);
-        }        
+        }
     }
 
     private Rect touchMove(MotionEvent event) {
         Rect areaToRefresh = null;
-        
+
         final float x = event.getX();
         final float y = event.getY();
 
@@ -530,7 +531,7 @@
 
         final float dx = Math.abs(x - previousX);
         final float dy = Math.abs(y - previousY);
-        
+
         if (dx >= GestureStroke.TOUCH_TOLERANCE || dy >= GestureStroke.TOUCH_TOLERANCE) {
             areaToRefresh = mInvalidRect;
 
@@ -538,55 +539,55 @@
             final int border = mInvalidateExtraBorder;
             areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border,
                     (int) mCurveEndX + border, (int) mCurveEndY + border);
-            
+
             float cX = mCurveEndX = (x + previousX) / 2;
             float cY = mCurveEndY = (y + previousY) / 2;
 
             mPath.quadTo(previousX, previousY, cX, cY);
-            
+
             // union with the control point of the new curve
             areaToRefresh.union((int) previousX - border, (int) previousY - border,
                     (int) previousX + border, (int) previousY + border);
-            
+
             // union with the end point of the new curve
             areaToRefresh.union((int) cX - border, (int) cY - border,
                     (int) cX + border, (int) cY + border);
 
             mX = x;
             mY = y;
-        }
 
-        mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+            mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
 
-        if (mHandleGestureActions && !mIsGesturing) {
-            mTotalLength += (float) Math.sqrt(dx * dx + dy * dy);
+            if (mHandleGestureActions && !mIsGesturing) {
+                mTotalLength += (float) Math.sqrt(dx * dx + dy * dy);
 
-            if (mTotalLength > mGestureStrokeLengthThreshold) {
-                final OrientedBoundingBox box =
-                        GestureUtilities.computeOrientedBoundingBox(mStrokeBuffer);
+                if (mTotalLength > mGestureStrokeLengthThreshold) {
+                    final OrientedBoundingBox box =
+                            GestureUtilities.computeOrientedBoundingBox(mStrokeBuffer);
 
-                float angle = Math.abs(box.orientation);
-                if (angle > 90) {
-                    angle = 180 - angle;
-                }
+                    float angle = Math.abs(box.orientation);
+                    if (angle > 90) {
+                        angle = 180 - angle;
+                    }
 
-                if (box.squareness > mGestureStrokeSquarenessTreshold ||
-                        (mOrientation == ORIENTATION_VERTICAL ?
-                                angle < mGestureStrokeAngleThreshold :
-                                angle > mGestureStrokeAngleThreshold)) {
+                    if (box.squareness > mGestureStrokeSquarenessTreshold ||
+                            (mOrientation == ORIENTATION_VERTICAL ?
+                                    angle < mGestureStrokeAngleThreshold :
+                                    angle > mGestureStrokeAngleThreshold)) {
 
-                    mIsGesturing = true;
-                    setCurrentColor(mCertainGestureColor);
+                        mIsGesturing = true;
+                        setCurrentColor(mCertainGestureColor);
+                    }
                 }
             }
-        }
 
-        // pass the event to handlers
-        final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
-        final int count = listeners.size();
-        for (int i = 0; i < count; i++) {
-            listeners.get(i).onGesture(this, event);
-        }        
+            // pass the event to handlers
+            final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
+            final int count = listeners.size();
+            for (int i = 0; i < count; i++) {
+                listeners.get(i).onGesture(this, event);
+            }
+        }
 
         return areaToRefresh;
     }
@@ -594,35 +595,45 @@
     private void touchUp(MotionEvent event, boolean cancel) {
         mIsListeningForGestures = false;
 
-        // add the stroke to the current gesture
-        mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer));
-        mStrokeBuffer.clear();
+        // A gesture wasn't started or was cancelled
+        if (mCurrentGesture != null) {
+            // add the stroke to the current gesture
+            mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer));
 
-        if (!cancel) {
-            // pass the event to handlers
-            final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
-            int count = listeners.size();
-            for (int i = 0; i < count; i++) {
-                listeners.get(i).onGestureEnded(this, event);
-            }
+            if (!cancel) {
+                // pass the event to handlers
+                final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
+                int count = listeners.size();
+                for (int i = 0; i < count; i++) {
+                    listeners.get(i).onGestureEnded(this, event);
+                }
 
-            if (mHandleGestureActions) {
-                clear(mFadeEnabled, mIsGesturing);
+                if (mHandleGestureActions) {
+                    clear(mFadeEnabled, mIsGesturing);
+                }
+            } else {
+                cancelGesture(event);
+
             }
         } else {
-            // pass the event to handlers
-            final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
-            final int count = listeners.size();
-            for (int i = 0; i < count; i++) {
-                listeners.get(i).onGestureCancelled(this, event);
-            }
-
-            clear(false);
+            cancelGesture(event);
         }
 
+        mStrokeBuffer.clear();
         mIsGesturing = false;
     }
 
+    private void cancelGesture(MotionEvent event) {
+        // pass the event to handlers
+        final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
+        final int count = listeners.size();
+        for (int i = 0; i < count; i++) {
+            listeners.get(i).onGestureCancelled(this, event);
+        }
+
+        clear(false);
+    }
+
     private void fireOnGesturePerformed() {
         final ArrayList<OnGesturePerformedListener> actionListeners =
                 mOnGesturePerformedListeners;
@@ -668,7 +679,7 @@
                 setPaintAlpha(255);
             }
 
-            invalidate();            
+            invalidate();
         }
     }
 
diff --git a/core/java/android/gesture/GestureStore.java b/core/java/android/gesture/GestureStore.java
new file mode 100644
index 0000000..ddf1c83
--- /dev/null
+++ b/core/java/android/gesture/GestureStore.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2008-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.gesture;
+
+import android.util.Log;
+import android.os.SystemClock;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.DataOutputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Map;
+
+import static android.gesture.GestureConstants.LOG_TAG;
+
+/**
+ * GestureLibrary maintains gesture examples and makes predictions on a new
+ * gesture
+ */
+//
+//    File format for GestureStore:
+//
+//                Nb. bytes   Java type   Description
+//                -----------------------------------
+//    Header
+//                2 bytes     short       File format version number
+//                4 bytes     int         Number of entries
+//    Entry
+//                X bytes     UTF String  Entry name
+//                4 bytes     int         Number of gestures
+//    Gesture
+//                8 bytes     long        Gesture ID
+//                4 bytes     int         Number of strokes
+//    Stroke
+//                4 bytes     int         Number of points
+//    Point
+//                4 bytes     float       X coordinate of the point
+//                4 bytes     float       Y coordinate of the point
+//                8 bytes     long        Time stamp
+//
+public class GestureStore {
+    public static final int SEQUENCE_INVARIANT = 1;
+    // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed
+    public static final int SEQUENCE_SENSITIVE = 2;
+
+    // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
+    public static final int ORIENTATION_INVARIANT = 1;
+    public static final int ORIENTATION_SENSITIVE = 2;
+
+    private static final short FILE_FORMAT_VERSION = 1;
+
+    private static final boolean PROFILE_LOADING_SAVING = false;
+
+    private int mSequenceType = SEQUENCE_SENSITIVE;
+    private int mOrientationStyle = ORIENTATION_SENSITIVE;
+
+    private final HashMap<String, ArrayList<Gesture>> mNamedGestures =
+            new HashMap<String, ArrayList<Gesture>>();
+
+    private Learner mClassifier;
+
+    private boolean mChanged = false;
+
+    public GestureStore() {
+        mClassifier = new InstanceLearner();
+    }
+
+    /**
+     * Specify how the gesture library will handle orientation. 
+     * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
+     * 
+     * @param style
+     */
+    public void setOrientationStyle(int style) {
+        mOrientationStyle = style;
+    }
+
+    public int getOrientationStyle() {
+        return mOrientationStyle;
+    }
+
+    /**
+     * @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
+     */
+    public void setSequenceType(int type) {
+        mSequenceType = type;
+    }
+
+    /**
+     * @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
+     */
+    public int getSequenceType() {
+        return mSequenceType;
+    }
+
+    /**
+     * Get all the gesture entry names in the library
+     * 
+     * @return a set of strings
+     */
+    public Set<String> getGestureEntries() {
+        return mNamedGestures.keySet();
+    }
+
+    /**
+     * Recognize a gesture
+     * 
+     * @param gesture the query
+     * @return a list of predictions of possible entries for a given gesture
+     */
+    public ArrayList<Prediction> recognize(Gesture gesture) {
+        Instance instance = Instance.createInstance(mSequenceType,
+                mOrientationStyle, gesture, null);
+        return mClassifier.classify(mSequenceType, instance.vector);
+    }
+
+    /**
+     * Add a gesture for the entry
+     * 
+     * @param entryName entry name
+     * @param gesture
+     */
+    public void addGesture(String entryName, Gesture gesture) {
+        if (entryName == null || entryName.length() == 0) {
+            return;
+        }
+        ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
+        if (gestures == null) {
+            gestures = new ArrayList<Gesture>();
+            mNamedGestures.put(entryName, gestures);
+        }
+        gestures.add(gesture);
+        mClassifier.addInstance(
+                Instance.createInstance(mSequenceType, mOrientationStyle, gesture, entryName));
+        mChanged = true;
+    }
+
+    /**
+     * Remove a gesture from the library. If there are no more gestures for the
+     * given entry, the gesture entry will be removed.
+     * 
+     * @param entryName entry name
+     * @param gesture
+     */
+    public void removeGesture(String entryName, Gesture gesture) {
+        ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
+        if (gestures == null) {
+            return;
+        }
+
+        gestures.remove(gesture);
+
+        // if there are no more samples, remove the entry automatically
+        if (gestures.isEmpty()) {
+            mNamedGestures.remove(entryName);
+        }
+
+        mClassifier.removeInstance(gesture.getID());
+
+        mChanged = true;
+    }
+
+    /**
+     * Remove a entry of gestures
+     * 
+     * @param entryName the entry name
+     */
+    public void removeEntry(String entryName) {
+        mNamedGestures.remove(entryName);
+        mClassifier.removeInstances(entryName);
+        mChanged = true;
+    }
+
+    /**
+     * Get all the gestures of an entry
+     * 
+     * @param entryName
+     * @return the list of gestures that is under this name
+     */
+    public ArrayList<Gesture> getGestures(String entryName) {
+        ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
+        if (gestures != null) {
+            return new ArrayList<Gesture>(gestures);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Save the gesture library
+     */
+    public void save(OutputStream stream) throws IOException {
+        save(stream, false);
+    }
+
+    public void save(OutputStream stream, boolean closeStream) throws IOException {
+        if (!mChanged) {
+            return;
+        }
+
+        DataOutputStream out = null;
+
+        try {
+            long start;
+            if (PROFILE_LOADING_SAVING) {
+                start = SystemClock.elapsedRealtime();
+            }
+
+            final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures;
+
+            out = new DataOutputStream((stream instanceof BufferedOutputStream) ? out :
+                    new BufferedOutputStream(out, GestureConstants.IO_BUFFER_SIZE));
+            // Write version number
+            out.writeShort(FILE_FORMAT_VERSION);
+            // Write number of entries
+            out.writeInt(maps.size());
+
+            for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) {
+                final String key = entry.getKey();
+                final ArrayList<Gesture> examples = entry.getValue();
+                final int count = examples.size();
+
+                // Write entry name
+                out.writeUTF(key);
+                // Write number of examples for this entry
+                out.writeInt(count);
+
+                for (int i = 0; i < count; i++) {
+                    examples.get(i).serialize(out);
+                }
+            }
+
+            out.flush();
+
+            if (PROFILE_LOADING_SAVING) {
+                long end = SystemClock.elapsedRealtime();
+                Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms");
+            }
+
+            mChanged = false;
+        } finally {
+            if (closeStream) GestureUtilities.closeStream(out);
+        }
+    }
+
+    /**
+     * Load the gesture library
+     */
+    public void load(InputStream stream) throws IOException {
+        load(stream, false);
+    }
+
+    public void load(InputStream stream, boolean closeStream) throws IOException {
+        DataInputStream in = null;
+        try {
+            in = new DataInputStream((stream instanceof BufferedInputStream) ? stream :
+                    new BufferedInputStream(stream, GestureConstants.IO_BUFFER_SIZE));
+
+            long start;
+            if (PROFILE_LOADING_SAVING) {
+                start = SystemClock.elapsedRealtime();
+            }
+
+            // Read file format version number
+            final short versionNumber = in.readShort();
+            switch (versionNumber) {
+                case 1:
+                    readFormatV1(in);
+                    break;
+            }
+
+            if (PROFILE_LOADING_SAVING) {
+                long end = SystemClock.elapsedRealtime();
+                Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms");
+            }
+        } finally {
+            if (closeStream) GestureUtilities.closeStream(in);
+        }
+    }
+
+    private void readFormatV1(DataInputStream in) throws IOException {
+        final Learner classifier = mClassifier;
+        final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures;
+        namedGestures.clear();
+
+        // Number of entries in the library
+        final int entriesCount = in.readInt();
+
+        for (int i = 0; i < entriesCount; i++) {
+            // Entry name
+            final String name = in.readUTF();
+            // Number of gestures
+            final int gestureCount = in.readInt();
+
+            final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount);
+            for (int j = 0; j < gestureCount; j++) {
+                final Gesture gesture = Gesture.deserialize(in);
+                gestures.add(gesture);
+                classifier.addInstance(
+                        Instance.createInstance(mSequenceType, mOrientationStyle, gesture, name));
+            }
+
+            namedGestures.put(name, gestures);
+        }
+    }
+    
+    Learner getLearner() {
+        return mClassifier;
+    }
+}
diff --git a/core/java/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java
index 0d7bc2d0..598eb85 100644
--- a/core/java/android/gesture/GestureStroke.java
+++ b/core/java/android/gesture/GestureStroke.java
@@ -17,7 +17,6 @@
 package android.gesture;
 
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.RectF;
@@ -31,7 +30,7 @@
  * A gesture stroke started on a touch down and ended on a touch up.
  */
 public class GestureStroke {
-    static final float TOUCH_TOLERANCE = 3;
+    static final float TOUCH_TOLERANCE = 8;
 
     public final RectF boundingBox;
 
@@ -147,10 +146,12 @@
         final float[] pts = GestureUtilities.temporalSampling(this, numSample);
         final RectF rect = boundingBox;
 
-        final Matrix matrix = new Matrix();
-        matrix.setTranslate(-rect.left, -rect.top);
-        matrix.postScale(width / rect.width(), height / rect.height());
-        matrix.mapPoints(pts);
+        GestureUtilities.translate(pts, -rect.left, -rect.top);
+        
+        float sx = width / rect.width();
+        float sy = height / rect.height();
+        float scale = sx > sy ? sy : sx;
+        GestureUtilities.scale(pts, scale, scale);
 
         float mX = 0;
         float mY = 0;
diff --git a/core/java/android/gesture/GestureUtilities.java b/core/java/android/gesture/GestureUtilities.java
index 4a3144c2..40d7029 100755
--- a/core/java/android/gesture/GestureUtilities.java
+++ b/core/java/android/gesture/GestureUtilities.java
@@ -17,7 +17,6 @@
 package android.gesture;
 
 import android.graphics.RectF;
-import android.graphics.Matrix;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -380,22 +379,17 @@
     }
 
     static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) {
-        Matrix tr = new Matrix();
-        tr.setTranslate(-centroid[0], -centroid[1]);
-        tr.mapPoints(points);
+        translate(points, -centroid[0], -centroid[1]);
 
         double[][] array = computeCoVariance(points);
         double[] targetVector = computeOrientation(array);
 
         float angle;
         if (targetVector[0] == 0 && targetVector[1] == 0) {
-            angle = -90;
+            angle = (float) -Math.PI/2;
         } else { // -PI<alpha<PI
             angle = (float) Math.atan2(targetVector[1], targetVector[0]);
-            angle = (float) (180 * angle / Math.PI);
-            Matrix trans = new Matrix();
-            trans.setRotate(-angle);
-            trans.mapPoints(points);
+            rotate(points, -angle);
         }
 
         float minx = Float.MAX_VALUE;
@@ -419,7 +413,7 @@
             }
         }
 
-        return new OrientedBoundingBox(angle, centroid[0], centroid[1], maxx - minx, maxy - miny);
+        return new OrientedBoundingBox((float) (angle * 180 / Math.PI), centroid[0], centroid[1], maxx - minx, maxy - miny);
     }
 
     private static double[] computeOrientation(double[][] covarianceMatrix) {
@@ -446,4 +440,36 @@
         }
         return targetVector;
     }
+    
+    
+    static float[] rotate(float[] points, double angle) {
+        double cos = Math.cos(angle);
+        double sin = Math.sin(angle);
+        int size = points.length;
+        for (int i = 0; i < size; i += 2) {
+            float x = (float) (points[i] * cos - points[i + 1] * sin);
+            float y = (float) (points[i] * sin + points[i + 1] * cos);
+            points[i] = x;
+            points[i + 1] = y;
+        }
+        return points;
+    }
+    
+    static float[] translate(float[] points, float dx, float dy) {
+        int size = points.length;
+        for (int i = 0; i < size; i += 2) {
+            points[i] += dx;
+            points[i + 1] += dy;
+        }
+        return points;
+    }
+    
+    static float[] scale(float[] points, float sx, float sy) {
+        int size = points.length;
+        for (int i = 0; i < size; i += 2) {
+            points[i] *= sx;
+            points[i + 1] *= sy;
+        }
+        return points;
+    }
 }
diff --git a/core/java/android/gesture/Instance.java b/core/java/android/gesture/Instance.java
index 7922fab..ef208ac 100755
--- a/core/java/android/gesture/Instance.java
+++ b/core/java/android/gesture/Instance.java
@@ -16,7 +16,6 @@
 
 package android.gesture;
 
-import android.graphics.Matrix;
 
 /**
  * An instance represents a sample if the label is available or a query if the
@@ -28,7 +27,9 @@
     private static final int PATCH_SAMPLE_SIZE = 16;
 
     private final static float[] ORIENTATIONS = {
-            0, 45, 90, 135, 180, -0, -45, -90, -135, -180
+            0, (float) (Math.PI / 4), (float) (Math.PI / 2), (float) (Math.PI * 3 / 4),
+            (float) Math.PI, -0, (float) (-Math.PI / 4), (float) (-Math.PI / 2),
+            (float) (-Math.PI * 3 / 4), (float) -Math.PI
     };
 
     // the feature vector
@@ -39,13 +40,13 @@
 
     // the id of the instance
     final long id;
-    
+
     private Instance(long id, float[] sample, String sampleName) {
         this.id = id;
         vector = sample;
         label = sampleName;
     }
-    
+
     private void normalize() {
         float[] sample = vector;
         float sum = 0;
@@ -55,7 +56,7 @@
             sum += sample[i] * sample[i];
         }
 
-        float magnitude = (float) Math.sqrt(sum);
+        float magnitude = (float)Math.sqrt(sum);
         for (int i = 0; i < size; i++) {
             sample[i] /= magnitude;
         }
@@ -68,11 +69,11 @@
      * @param label
      * @return the instance
      */
-    static Instance createInstance(int samplingType, Gesture gesture, String label) {
+    static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) {
         float[] pts;
         Instance instance;
-        if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) {
-            pts = temporalSampler(samplingType, gesture);
+        if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) {
+            pts = temporalSampler(orientationType, gesture);
             instance = new Instance(gesture.getID(), pts, label);
             instance.normalize();
         } else {
@@ -81,20 +82,19 @@
         }
         return instance;
     }
-    
+
     private static float[] spatialSampler(Gesture gesture) {
         return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
     }
 
-    private static float[] temporalSampler(int samplingType, Gesture gesture) {
+    private static float[] temporalSampler(int orientationType, Gesture gesture) {
         float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
                 SEQUENCE_SAMPLE_SIZE);
         float[] center = GestureUtilities.computeCentroid(pts);
-        float orientation = (float) Math.atan2(pts[1] - center[1], pts[0] - center[0]);
-        orientation *= 180 / Math.PI;
+        float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
 
         float adjustment = -orientation;
-        if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) {
+        if (orientationType == GestureStore.ORIENTATION_SENSITIVE) {
             int count = ORIENTATIONS.length;
             for (int i = 0; i < count; i++) {
                 float delta = ORIENTATIONS[i] - orientation;
@@ -104,10 +104,8 @@
             }
         }
 
-        Matrix m = new Matrix();
-        m.setTranslate(-center[0], -center[1]);
-        m.postRotate(adjustment);
-        m.mapPoints(pts);
+        GestureUtilities.translate(pts, -center[0], -center[1]);
+        GestureUtilities.rotate(pts, adjustment);
 
         return pts;
     }
diff --git a/core/java/android/gesture/InstanceLearner.java b/core/java/android/gesture/InstanceLearner.java
index 1739cdc..00cdadc 100644
--- a/core/java/android/gesture/InstanceLearner.java
+++ b/core/java/android/gesture/InstanceLearner.java
@@ -16,14 +16,9 @@
 
 package android.gesture;
 
-import android.util.Config;
-import android.util.Log;
-import static android.gesture.GestureConstants.*;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Iterator;
 import java.util.TreeMap;
 
 /**
@@ -32,7 +27,7 @@
 
 class InstanceLearner extends Learner {
     @Override
-    ArrayList<Prediction> classify(int gestureType, float[] vector) {
+    ArrayList<Prediction> classify(int sequenceType, float[] vector) {
         ArrayList<Prediction> predictions = new ArrayList<Prediction>();
         ArrayList<Instance> instances = getInstances();
         int count = instances.size();
@@ -43,7 +38,7 @@
                 continue;
             }
             double distance;
-            if (gestureType == GestureLibrary.SEQUENCE_SENSITIVE) {
+            if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) {
                 distance = GestureUtilities.cosineDistance(sample.vector, vector);
             } else {
                 distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);
diff --git a/core/java/android/gesture/LetterRecognizer.java b/core/java/android/gesture/LetterRecognizer.java
index 9e801ed..580fc26 100644
--- a/core/java/android/gesture/LetterRecognizer.java
+++ b/core/java/android/gesture/LetterRecognizer.java
@@ -23,6 +23,7 @@
 import java.io.BufferedInputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -31,10 +32,9 @@
 import static android.gesture.GestureConstants.LOG_TAG;
 
 public class LetterRecognizer {
-    public final static int RECOGNIZER_LATIN_LOWERCASE = 0;
     static final String GESTURE_FILE_NAME = "letters.gestures";
 
-    private final static int ADJUST_RANGE = 3;    
+    private final static int ADJUST_RANGE = 3;
 
     private SigmoidUnit[] mHiddenLayer;
     private SigmoidUnit[] mOutputLayer;
@@ -42,8 +42,8 @@
     private final String[] mClasses;
 
     private final int mPatchSize;
-    
-    private GestureLibrary mGestureLibrary;
+
+    private GestureLibrary mGestureStore;
 
     private final Comparator<Prediction> mComparator = new PredictionComparator();
 
@@ -69,15 +69,6 @@
         }
     }
 
-    public static LetterRecognizer getLetterRecognizer(Context context, int type) {
-        switch (type) {
-            case RECOGNIZER_LATIN_LOWERCASE: {
-                return createFromResource(context, com.android.internal.R.raw.latin_lowercase);
-            }
-        }
-        return null;
-    }
-
     private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) {
         mPatchSize = (int) Math.sqrt(numOfInput);
         mHiddenLayer = new SigmoidUnit[numOfHidden];
@@ -137,14 +128,18 @@
         return output;
     }
 
-    private static LetterRecognizer createFromResource(Context context, int resourceID) {
+    static LetterRecognizer createFromResource(Context context, int resourceID) {
         final Resources resources = context.getResources();
+        final InputStream stream = resources.openRawResource(resourceID);
+        return createFromStream(stream);
+    }
 
+    static LetterRecognizer createFromStream(InputStream stream) {
         DataInputStream in = null;
         LetterRecognizer classifier = null;
 
         try {
-            in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID),
+            in = new DataInputStream(new BufferedInputStream(stream,
                     GestureConstants.IO_BUFFER_SIZE));
 
             final int version = in.readShort();
@@ -206,49 +201,49 @@
     }
 
     /**
-     * TODO: Publish this API once we figure out where we should save the personzlied
+     * TODO: Publish this API once we figure out where we should save the personalized
      * gestures, and how to do so across all apps
      *
      * @hide
      */
     public boolean save() {
-        if (mGestureLibrary != null) {
-            return mGestureLibrary.save();
+        if (mGestureStore != null) {
+            return mGestureStore.save();
         }
         return false;
     }
 
     /**
-     * TODO: Publish this API once we figure out where we should save the personzlied
+     * TODO: Publish this API once we figure out where we should save the personalized
      * gestures, and how to do so across all apps
      *
      * @hide
      */
     public void setPersonalizationEnabled(boolean enabled) {
         if (enabled) {
-            mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME);
-            mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT);
-            mGestureLibrary.load();
+            mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME);
+            mGestureStore.setSequenceType(GestureStore.SEQUENCE_INVARIANT);
+            mGestureStore.load();
         } else {
-            mGestureLibrary = null;
+            mGestureStore = null;
         }
     }
 
     /**
-     * TODO: Publish this API once we figure out where we should save the personzlied
+     * TODO: Publish this API once we figure out where we should save the personalized
      * gestures, and how to do so across all apps
      *
      * @hide
      */
     public void addExample(String letter, Gesture example) {
-        if (mGestureLibrary != null) {
-            mGestureLibrary.addGesture(letter, example);
+        if (mGestureStore != null) {
+            mGestureStore.addGesture(letter, example);
         }
     }
-    
+
     private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) {
-        if (mGestureLibrary != null) {
-            final ArrayList<Prediction> results = mGestureLibrary.recognize(query);
+        if (mGestureStore != null) {
+            final ArrayList<Prediction> results = mGestureStore.recognize(query);
             final HashMap<String, Prediction> topNList = new HashMap<String, Prediction>();
 
             for (int j = 0; j < ADJUST_RANGE; j++) {
diff --git a/core/java/android/gesture/LetterRecognizers.java b/core/java/android/gesture/LetterRecognizers.java
new file mode 100644
index 0000000..e3f45a0
--- /dev/null
+++ b/core/java/android/gesture/LetterRecognizers.java
@@ -0,0 +1,65 @@
+/*
+ * 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.gesture;
+
+import android.content.Context;
+import android.util.Log;
+import static android.gesture.GestureConstants.LOG_TAG;
+import static android.gesture.LetterRecognizer.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+public final class LetterRecognizers {
+    public final static int RECOGNIZER_LATIN_LOWERCASE = 0;
+
+    private LetterRecognizers() {
+    }
+
+    public static LetterRecognizer fromType(Context context, int type) {
+        switch (type) {
+            case RECOGNIZER_LATIN_LOWERCASE: {
+                return createFromResource(context, com.android.internal.R.raw.latin_lowercase);
+            }
+        }
+        return null;
+    }
+
+    public static LetterRecognizer fromResource(Context context, int resourceId) {
+        return createFromResource(context, resourceId);
+    }
+
+    public static LetterRecognizer fromFile(String path) {
+        return fromFile(new File(path));
+    }
+
+    public static LetterRecognizer fromFile(File file) {
+        try {
+            return createFromStream(new FileInputStream(file));
+        } catch (FileNotFoundException e) {
+            Log.d(LOG_TAG, "Failed to load handwriting data from file " + file, e);
+        }
+        return null;
+    }
+
+    public static LetterRecognizer fromStream(InputStream stream) {
+        return createFromStream(stream);
+    }
+}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 963875d..830b0bd 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -117,7 +117,7 @@
          * new changes in behavior:</p>
          * <ul>
          * <li> They must explicitly request the
-         * {@link android.Manifest.permission#WRITE_SDCARD} permission to be
+         * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission to be
          * able to modify the contents of the SD card.  (Apps targeting
          * earlier versions will always request the permission.)
          * </ul>
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index 76e4f47..65e83c7 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -18,6 +18,7 @@
 
 import android.util.Log;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -35,19 +36,19 @@
 public class MemoryFile
 {
     private static String TAG = "MemoryFile";
- 
-    // returns fd
-    private native int native_open(String name, int length);
-    // returns memory address for ashmem region
-    private native int native_mmap(int fd, int length);
-    private native void native_close(int fd);
-    private native int native_read(int fd, int address, byte[] buffer, 
-            int srcOffset, int destOffset, int count, boolean isUnpinned);
-    private native void native_write(int fd, int address, byte[] buffer, 
-            int srcOffset, int destOffset, int count, boolean isUnpinned);
-    private native void native_pin(int fd, boolean pin);
 
-    private int mFD;        // ashmem file descriptor
+    private static native FileDescriptor native_open(String name, int length) throws IOException;
+    // returns memory address for ashmem region
+    private static native int native_mmap(FileDescriptor fd, int length) throws IOException;
+    private static native void native_munmap(int addr, int length) throws IOException;
+    private static native void native_close(FileDescriptor fd);
+    private static native int native_read(FileDescriptor fd, int address, byte[] buffer,
+            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
+    private static native void native_write(FileDescriptor fd, int address, byte[] buffer,
+            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
+    private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
+
+    private FileDescriptor mFD;        // ashmem file descriptor
     private int mAddress;   // address of ashmem memory
     private int mLength;    // total length of our ashmem region
     private boolean mAllowPurging = false;  // true if our ashmem region is unpinned
@@ -57,8 +58,9 @@
      *
      * @param name optional name for the file (can be null).
      * @param length of the memory file in bytes.
+     * @throws IOException if the memory file could not be created.
      */
-    public MemoryFile(String name, int length) {
+    public MemoryFile(String name, int length) throws IOException {
         mLength = length;
         mFD = native_open(name, length);
         mAddress = native_mmap(mFD, length);
@@ -68,15 +70,40 @@
      * Closes and releases all resources for the memory file.
      */
     public void close() {
-        if (mFD > 0) {
+        deactivate();
+        if (!isClosed()) {
             native_close(mFD);
-            mFD = 0;
         }
     }
 
+    private void deactivate() {
+        if (!isDeactivated()) {
+            try {
+                native_munmap(mAddress, mLength);
+                mAddress = 0;
+            } catch (IOException ex) {
+                Log.e(TAG, ex.toString());
+            }
+        }
+    }
+
+    /**
+     * Checks whether the memory file has been deactivated.
+     */
+    private boolean isDeactivated() {
+        return mAddress == 0;
+    }
+
+    /**
+     * Checks whether the memory file has been closed.
+     */
+    private boolean isClosed() {
+        return !mFD.valid();
+    }
+
     @Override
     protected void finalize() {
-        if (mFD > 0) {
+        if (!isClosed()) {
             Log.e(TAG, "MemoryFile.finalize() called while ashmem still open");
             close();
         }
@@ -131,7 +158,6 @@
      @return OutputStream
      */
      public OutputStream getOutputStream() {
-
         return new MemoryOutputStream();
     }
 
@@ -144,9 +170,13 @@
      * @param destOffset offset into the byte array buffer to read into.
      * @param count number of bytes to read.
      * @return number of bytes read.
+     * @throws IOException if the memory file has been purged or deactivated.
      */
     public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count) 
             throws IOException {
+        if (isDeactivated()) {
+            throw new IOException("Can't read from deactivated memory file.");
+        }
         if (destOffset < 0 || destOffset > buffer.length || count < 0
                 || count > buffer.length - destOffset
                 || srcOffset < 0 || srcOffset > mLength
@@ -164,9 +194,13 @@
      * @param srcOffset offset into the byte array buffer to write from.
      * @param destOffset offset  into the memory file to write to.
      * @param count number of bytes to write.
+     * @throws IOException if the memory file has been purged or deactivated.
      */
     public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
             throws IOException {
+        if (isDeactivated()) {
+            throw new IOException("Can't write to deactivated memory file.");
+        }
         if (srcOffset < 0 || srcOffset > buffer.length || count < 0
                 || count > buffer.length - srcOffset
                 || destOffset < 0 || destOffset > mLength
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index abd6934..7d03801 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -151,6 +151,9 @@
                 int presentation, int callType, long start, int duration) {
             final ContentResolver resolver = context.getContentResolver();
 
+            // TODO(Moto): Which is correct: original code, this only changes the
+            // number if the number is empty and never changes the caller info name.
+        if (false) {
             if (TextUtils.isEmpty(number)) {
                 if (presentation == Connection.PRESENTATION_RESTRICTED) {
                     number = CallerInfo.PRIVATE_NUMBER;
@@ -160,7 +163,22 @@
                     number = CallerInfo.UNKNOWN_NUMBER;
                 }
             }
+        } else {
+            // NEWCODE: From Motorola
 
+            //If this is a private number then set the number to Private, otherwise check
+            //if the number field is empty and set the number to Unavailable
+            if (presentation == Connection.PRESENTATION_RESTRICTED) {
+                number = CallerInfo.PRIVATE_NUMBER;
+                ci.name = "";
+            } else if (presentation == Connection.PRESENTATION_PAYPHONE) {
+                number = CallerInfo.PAYPHONE_NUMBER;
+                ci.name = "";
+            } else if (TextUtils.isEmpty(number) || presentation == Connection.PRESENTATION_UNKNOWN) {
+                number = CallerInfo.UNKNOWN_NUMBER;
+                ci.name = "";
+            }
+        }
             ContentValues values = new ContentValues(5);
 
             values.put(NUMBER, number);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 559f224..5d10675 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2838,12 +2838,12 @@
          * out without asking for use permit, to limit the un-authorized SMS
          * usage.
          */
-        public static final String SMS_OUTGOING_CEHCK_INTERVAL_MS =
+        public static final String SMS_OUTGOING_CHECK_INTERVAL_MS =
                 "sms_outgoing_check_interval_ms";
 
         /**
          * The number of outgoing SMS sent without asking for user permit
-         * (of {@link #SMS_OUTGOING_CEHCK_INTERVAL_MS}
+         * (of {@link #SMS_OUTGOING_CHECK_INTERVAL_MS}
          */
         public static final String SMS_OUTGOING_CEHCK_MAX_COUNT =
                 "sms_outgoing_check_max_count";
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index a4145c4..4078fa6 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -466,6 +466,24 @@
          */
         public static final class Intents {
             /**
+             * Set by BroadcastReceiver. Indicates the message was handled
+             * successfully.
+             */
+            public static final int RESULT_SMS_HANDLED = 1;
+
+            /**
+             * Set by BroadcastReceiver. Indicates a generic error while
+             * processing the message.
+             */
+            public static final int RESULT_SMS_GENERIC_ERROR = 2;
+
+            /**
+             * Set by BroadcastReceiver. Indicates insufficient memory to store
+             * the message.
+             */
+            public static final int RESULT_SMS_OUT_OF_MEMORY = 3;
+
+            /**
              * Broadcast Action: A new text based SMS message has been received
              * by the device. The intent will have the following extra
              * values:</p>
@@ -476,7 +494,10 @@
              * </ul>
              *
              * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}</p>
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String SMS_RECEIVED_ACTION =
@@ -493,7 +514,10 @@
              * </ul>
              *
              * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}</p>
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String DATA_SMS_RECEIVED_ACTION =
@@ -510,6 +534,9 @@
              *   <li><em>pduType (Integer)</em> - The WAP PDU type</li>
              *   <li><em>data</em> - The data payload of the message</li>
              * </ul>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String WAP_PUSH_RECEIVED_ACTION =
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
index 6ed32b5..b4abfda 100644
--- a/core/java/android/speech/IRecognitionListener.aidl
+++ b/core/java/android/speech/IRecognitionListener.aidl
@@ -17,6 +17,7 @@
 package android.speech;
 
 import android.os.Bundle;
+import android.speech.RecognitionResult;
 
 /**
  * Listener for speech recognition events, used with RecognitionService.
@@ -43,13 +44,19 @@
     /** Called after the user stops speaking. */
     void onEndOfSpeech();
 
-    /** A network or recognition error occurred. */
-    void onError(in String error);
+    /**
+     * A network or recognition error occurred.
+     * TODO: right now, the error code is given in voice search package
+     * (vendor/google/apps/src/com/google/android/voicesearch/speechservice/SpeechServiceListener.java)
+     * we need to find a place to define common error code.
+     */
+    void onError(in int error);
 
     /** 
-     * Called when recognition transcripts are ready.
-     * results: an ordered list of the most likely transcripts (N-best list).
-     * @hide
+     * Called when recognition results are ready.
+     * @param results: an ordered list of the most likely results (N-best list).
+     * @param key: a key associated with the results. The same results can
+     * be retrieved asynchronously later using the key, if available. 
      */
-    void onResults(in List<String> results);
+    void onResults(in List<RecognitionResult> results, long key);
 }
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
index 36d12e9a..a18c380 100644
--- a/core/java/android/speech/IRecognitionService.aidl
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.speech.IRecognitionListener;
+import android.speech.RecognitionResult;
 
 // A Service interface to speech recognition. Call startListening when
 // you want to begin capturing audio; RecognitionService will automatically
@@ -29,6 +30,8 @@
     // see RecognizerIntent.java for constants used to specify the intent.
     void startListening(in Intent recognizerIntent,
         in IRecognitionListener listener);
+        
+    List<RecognitionResult> getRecognitionResults(in long key);
 
     void cancel();
 }
diff --git a/core/java/android/speech/RecognitionResult.aidl b/core/java/android/speech/RecognitionResult.aidl
new file mode 100644
index 0000000..59e53ab
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.speech;
+
+parcelable RecognitionResult;
diff --git a/core/java/android/speech/RecognitionResult.java b/core/java/android/speech/RecognitionResult.java
new file mode 100644
index 0000000..c3ac484
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ * 
+ * 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.speech;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * RecognitionResult is a passive object that stores a single recognized
+ * query and its search result.
+ * TODO: revisit and improve. May be we should have a separate result
+ * object for each type, and put them (type/value) in bundle?
+ * 
+ * {@hide}
+ */
+public class RecognitionResult implements Parcelable {
+
+    /**
+     * Type of the recognition results. 
+     */
+    public static final int RAW_RECOGNITION_RESULT  = 0;
+    public static final int WEB_SEARCH_RESULT  = 1;
+    public static final int CONTACT_RESULT = 2;
+
+    /**
+     * A factory method to create a raw RecognitionResult
+     * 
+     * @param sentence the recognized text.
+     */
+    public static RecognitionResult newRawRecognitionResult(String sentence) {
+        return new RecognitionResult(RAW_RECOGNITION_RESULT, sentence, null, null);
+    }
+
+    /**
+     * A factory method to create RecognitionResult for contacts.
+     * 
+     * @param contact the contact name.
+     * @param phoneType the phone type.
+     */
+    public static RecognitionResult newContactResult(String contact, int phoneType) {
+        return new RecognitionResult(CONTACT_RESULT, contact, phoneType);
+    }
+
+    /**
+     * A factory method to create a RecognitionResult for Web Search Query.
+     * 
+     * @param query the query string. 
+     * @param html the html page of the search result.
+     * @param url  the url that performs the search with the query.
+     */
+    public static RecognitionResult newWebResult(String query, String html, String url) {
+        return new RecognitionResult(WEB_SEARCH_RESULT, query, html, url);
+    }
+    
+    public static final Parcelable.Creator<RecognitionResult> CREATOR
+            = new Parcelable.Creator<RecognitionResult>() {
+
+        public RecognitionResult createFromParcel(Parcel in) {
+            return new RecognitionResult(in);
+        }
+        
+        public RecognitionResult[] newArray(int size) {
+            return new RecognitionResult[size];
+        }
+    };
+
+    /**
+     * Result type.
+     */
+    public final int mResultType;
+
+     /**
+     * The recognized string when mResultType is WEB_SEARCH_RESULT.
+     * The name of the contact when mResultType is CONTACT_RESULT.
+     */
+    public final String mText;
+
+    /**
+     * The HTML result page for the query. If this is null, then the
+     * application must use the url field to get the HTML result page.
+     */
+    public final String mHtml;
+
+    /**
+     * The url to get the result page for the query string.  The
+     * application must use this url instead of performing the search
+     * with the query.
+     */
+    public final String mUrl;
+
+    /** Phone number type. This is valid only when mResultType == CONTACT_RESULT */
+    public final int mPhoneType;
+
+    private RecognitionResult(int type, String query, String html, String url) {
+        mResultType = type;
+        mText = query;
+        mHtml = html;
+        mUrl = url;
+        mPhoneType = -1;
+    }
+
+    private RecognitionResult(int type, String query, int at) {
+        mResultType = type;
+        mText = query;
+        mPhoneType = at;
+        mHtml = null;
+        mUrl = null;
+    }
+    
+    private RecognitionResult(Parcel in) {
+        mResultType = in.readInt();
+        mText = in.readString();
+        mHtml= in.readString();
+        mUrl= in.readString();
+        mPhoneType = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mResultType);
+        out.writeString(mText);
+        out.writeString(mHtml);
+        out.writeString(mUrl);
+        out.writeInt(mPhoneType);
+    }
+    
+    
+    @Override
+    public String toString() {
+        String resultType[] = { "RAW", "WEB", "CONTACT" };
+        return "[type=" +  resultType[mResultType] +
+                ", text=" + mText+ ", mUrl=" + mUrl + ", html=" + mHtml + "]";
+    }
+
+    public int describeContents() {
+        // no special description
+        return 0;
+    }
+}
diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java
index 650c0fd..a8c7868 100644
--- a/core/java/android/speech/RecognitionServiceUtil.java
+++ b/core/java/android/speech/RecognitionServiceUtil.java
@@ -21,6 +21,9 @@
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.speech.RecognitionResult;
+import android.util.Log;
 
 import java.util.List;
 
@@ -56,6 +59,11 @@
     public static final Intent sDefaultIntent = new Intent(
             RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
 
+    // Recognize request parameters
+    public static final String USE_LOCATION = "useLocation";
+    public static final String CONTACT_AUTH_TOKEN = "contactAuthToken";
+    
+    // Bundles
     public static final String NOISE_LEVEL = "NoiseLevel";
     public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio";
 
@@ -72,8 +80,8 @@
         public void onRmsChanged(float rmsdB) {}
         public void onBufferReceived(byte[] buf) {}
         public void onEndOfSpeech() {}
-        public void onError(String error) {}
-        public void onResults(List<String> results) {}
+        public void onError(int error) {}
+        public void onResults(List<RecognitionResult> results, long key) {}
     }
 
     /**
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index b121e60..584e83f 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -106,7 +106,7 @@
      */
     public static final char[] CHARACTERS = new char[] {
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*',
-            '+', '-', '(', ')', ',', '/', 'N', '.', ' '
+            '+', '-', '(', ')', ',', '/', 'N', '.', ' ', ';'
         };
 
     private static DialerKeyListener sInstance;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 3c827a0..ec02143 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -52,6 +52,7 @@
 import android.gesture.Gesture;
 import android.gesture.LetterRecognizer;
 import android.gesture.Prediction;
+import android.gesture.LetterRecognizers;
 
 import com.android.internal.R;
 
@@ -94,7 +95,7 @@
     public static final int TRANSCRIPT_MODE_NORMAL = 1;
     /**
      * The list will automatically scroll to the bottom, no matter what items
-     * are currently visible. 
+     * are currently visible.
      *
      * @see #setTranscriptMode(int)
      */
@@ -156,7 +157,7 @@
      * Indicates the view is in the process of being flung
      */
     static final int TOUCH_MODE_FLING = 4;
-    
+
     /**
      * Indicates that the user is currently dragging the fast scroll thumb
      */
@@ -349,7 +350,7 @@
      * bitmap cache after scrolling.
      */
     boolean mScrollingCacheEnabled;
-    
+
     /**
      * Whether or not to enable the fast scroll feature on this list
      */
@@ -422,7 +423,7 @@
      * The last CheckForTap runnable we posted, if any
      */
     private Runnable mPendingCheckForTap;
-    
+
     /**
      * The last CheckForKeyLongPress runnable we posted, if any
      */
@@ -576,7 +577,7 @@
 
         int color = a.getColor(R.styleable.AbsListView_cacheColorHint, 0);
         setCacheColorHint(color);
-        
+
         boolean enableFastScroll = a.getBoolean(R.styleable.AbsListView_fastScrollEnabled, false);
         setFastScrollEnabled(enableFastScroll);
 
@@ -605,7 +606,7 @@
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
         mDensityScale = getContext().getResources().getDisplayMetrics().density;
     }
-    
+
     /**
      * <p>Sets the type of gestures to use with this list. When gestures are enabled,
      * that is if the <code>gestures</code> parameter is not {@link #GESTURES_NONE},
@@ -663,7 +664,7 @@
      * @see #GESTURES_NONE
      * @see #GESTURES_JUMP
      * @see #GESTURES_FILTER
-     * @see #setGestures(int) 
+     * @see #setGestures(int)
      */
     @ViewDebug.ExportedProperty(mapping = {
         @ViewDebug.IntToString(from = GESTURES_NONE, to = "NONE"),
@@ -737,7 +738,7 @@
             mGesturesOverlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
             mGesturesOverlay.addOnGesturePerformedListener(new GesturesProcessor());
 
-            mPreviousGesturing = false;            
+            mPreviousGesturing = false;
         }
     }
 
@@ -778,10 +779,10 @@
     }
 
     /**
-     * Enables fast scrolling by letting the user quickly scroll through lists by 
-     * dragging the fast scroll thumb. The adapter attached to the list may want 
+     * Enables fast scrolling by letting the user quickly scroll through lists by
+     * dragging the fast scroll thumb. The adapter attached to the list may want
      * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
-     * jump between sections of the list. 
+     * jump between sections of the list.
      * @see SectionIndexer
      * @see #isFastScrollEnabled()
      * @param enabled whether or not to enable fast scrolling
@@ -799,7 +800,7 @@
             }
         }
     }
-    
+
     /**
      * Returns the current state of the fast scroll feature.
      * @see #setFastScrollEnabled(boolean)
@@ -809,10 +810,10 @@
     public boolean isFastScrollEnabled() {
         return mFastScrollEnabled;
     }
-    
+
     /**
      * If fast scroll is visible, then don't draw the vertical scrollbar.
-     * @hide 
+     * @hide
      */
     @Override
     protected boolean isVerticalScrollBarHidden() {
@@ -830,11 +831,11 @@
      * When smooth scrollbar is disabled, the position and size of the scrollbar thumb
      * is based solely on the number of items in the adapter and the position of the
      * visible items inside the adapter. This provides a stable scrollbar as the user
-     * navigates through a list of items with varying heights. 
+     * navigates through a list of items with varying heights.
      *
      * @param enabled Whether or not to enable smooth scrollbar.
      *
-     * @see #setSmoothScrollbarEnabled(boolean) 
+     * @see #setSmoothScrollbarEnabled(boolean)
      * @attr ref android.R.styleable#AbsListView_smoothScrollbar
      */
     public void setSmoothScrollbarEnabled(boolean enabled) {
@@ -1142,7 +1143,7 @@
     /**
      * Sets the initial value for the text filter.
      * @param filterText The text to use for the filter.
-     * 
+     *
      * @see #setTextFilterEnabled
      */
     public void setFilterText(String filterText) {
@@ -1168,7 +1169,7 @@
     }
 
     /**
-     * Returns the list's text filter, if available. 
+     * Returns the list's text filter, if available.
      * @return the list's text filter or null if filtering isn't enabled
      */
     public CharSequence getTextFilter() {
@@ -1177,7 +1178,7 @@
         }
         return null;
     }
-    
+
     @Override
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
@@ -1570,7 +1571,7 @@
         if (mInstallGesturesOverlay) {
             installGesturesOverlay();
             positionGesturesPopup();
-        } else if (mGesturesPopup != null) {
+        } else if (mGesturesPopup != null && mGesturesPopup.isShowing()) {
             mGesturesPopup.update(w, h);
         }
     }
@@ -1740,7 +1741,7 @@
             System.arraycopy(state, enabledPos + 1, state, enabledPos,
                     state.length - enabledPos - 1);
         }
-        
+
         return state;
     }
 
@@ -1851,16 +1852,16 @@
      */
     private class WindowRunnnable {
         private int mOriginalAttachCount;
-        
+
         public void rememberWindowAttachCount() {
             mOriginalAttachCount = getWindowAttachCount();
         }
-        
+
         public boolean sameWindow() {
             return hasWindowFocus() && getWindowAttachCount() == mOriginalAttachCount;
         }
     }
-    
+
     private class PerformClick extends WindowRunnnable implements Runnable {
         View mChild;
         int mClickMotionPosition;
@@ -1887,7 +1888,7 @@
                 final long longPressId = mAdapter.getItemId(mMotionPosition);
 
                 boolean handled = false;
-                if (sameWindow() && !mDataChanged) { 
+                if (sameWindow() && !mDataChanged) {
                     handled = performLongPress(child, longPressPosition, longPressId);
                 }
                 if (handled) {
@@ -1901,7 +1902,7 @@
             }
         }
     }
-    
+
     private class CheckForKeyLongPress extends WindowRunnnable implements Runnable {
         public void run() {
             if (isPressed() && mSelectedPosition >= 0) {
@@ -1930,7 +1931,7 @@
         boolean handled = false;
 
         dismissGesturesPopup();
-        
+
         if (mOnItemLongClickListener != null) {
             handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
                     longPressPosition, longPressId);
@@ -2079,7 +2080,7 @@
                             mTouchMode = TOUCH_MODE_DONE_WAITING;
                         }
                     } else {
-                        mTouchMode = TOUCH_MODE_DONE_WAITING;                        
+                        mTouchMode = TOUCH_MODE_DONE_WAITING;
                     }
                 }
             }
@@ -2138,7 +2139,7 @@
             boolean intercepted = mFastScroller.onTouchEvent(ev);
             if (intercepted) {
                 return true;
-            }            
+            }
         }
 
         final int action = ev.getAction();
@@ -2326,10 +2327,10 @@
             }
 
             setPressed(false);
-            
+
             // Need to redraw since we probably aren't drawing the selector anymore
             invalidate();
-            
+
             final Handler handler = getHandler();
             if (handler != null) {
                 handler.removeCallbacks(mPendingCheckForLongPress);
@@ -2373,7 +2374,7 @@
 
         return true;
     }
-    
+
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
@@ -2388,14 +2389,14 @@
         int x = (int) ev.getX();
         int y = (int) ev.getY();
         View v;
-        
+
         if (mFastScroller != null) {
             boolean intercepted = mFastScroller.onInterceptTouchEvent(ev);
             if (intercepted) {
                 return true;
             }
         }
-        
+
         switch (action) {
         case MotionEvent.ACTION_DOWN: {
             int motionPosition = findMotionRow(y);
@@ -3245,7 +3246,7 @@
         }
         return null;
     }
-    
+
     /**
      * For filtering we proxy an input connection to an internal text editor,
      * and this allows the proxying to happen.
@@ -3254,7 +3255,7 @@
     public boolean checkInputConnectionProxy(View view) {
         return view == mTextFilter;
     }
-    
+
     /**
      * Creates the window for the text filter and populates it with an EditText field;
      *
@@ -3647,7 +3648,7 @@
             mCurrentScrap = scrapViews[0];
             mScrapViews = scrapViews;
         }
-        
+
         public boolean shouldRecycleViewType(int viewType) {
             return viewType >= 0;
         }
@@ -3862,11 +3863,10 @@
         private final char[] mHolder;
 
         GesturesProcessor() {
-            mRecognizer = LetterRecognizer.getLetterRecognizer(getContext(),
-                    LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE);
+            mRecognizer = LetterRecognizers.fromType(getContext(),
+                    LetterRecognizers.RECOGNIZER_LATIN_LOWERCASE);
             if (mRecognizer == null) {
-                dismissGesturesPopup();
-                mGestures = GESTURES_NONE;
+                setGestures(GESTURES_NONE);
             }
             if (mGestures == GESTURES_FILTER) {
                 mKeyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 5fa00e7..c4b5ef8 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -124,25 +124,25 @@
         if(pkg == null) {
             return;
         }
-        // Extract shared user permissions if any
+        // Get requested permissions
+        if (pkg.requestedPermissions != null) {
+            ArrayList<String> strList = pkg.requestedPermissions;
+            int size = strList.size();
+            if (size > 0) {
+                extractPerms(strList.toArray(new String[size]), permSet);
+            }
+        }
+        // Get permissions related to  shared user if any
         if(pkg.mSharedUserId != null) {
             int sharedUid;
             try {
                 sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId);
+                getAllUsedPermissions(sharedUid, permSet);
             } catch (NameNotFoundException e) {
                 Log.w(TAG, "Could'nt retrieve shared user id for:"+pkg.packageName);
-                return;
             }
-            getAllUsedPermissions(sharedUid, permSet);
-        } else {
-            ArrayList<String> strList = pkg.requestedPermissions;
-            int size;
-            if((strList == null) || ((size = strList.size()) == 0)) {
-                return;
-            }
-            // Extract permissions defined in current package
-            extractPerms(strList.toArray(new String[size]), permSet);
         }
+        // Retrieve list of permissions
         for(PermissionInfo tmpInfo : permSet) {
             mPermsList.add(tmpInfo);
         }
@@ -176,14 +176,9 @@
             Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
             return;
         }
-        if(pkgInfo == null) {
-            return;
+        if ((pkgInfo != null) && (pkgInfo.requestedPermissions != null)) {
+            extractPerms(pkgInfo.requestedPermissions, permSet);
         }
-        String strList[] = pkgInfo.requestedPermissions;
-        if(strList == null) {
-            return;
-        }
-        extractPerms(strList, permSet);
     }
     
     private void extractPerms(String strList[], Set<PermissionInfo> permSet) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 10d8f55c..99cf6f8c 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2851,9 +2851,15 @@
             final int first = mFirstPosition;
             final boolean areAllItemsSelectable = mAreAllItemsSelectable;
             final ListAdapter adapter = mAdapter;
-            final boolean isOpaque = isOpaque();
-            if (isOpaque && mDividerPaint == null) {
+            // If the list is opaque *and* the background is not, we want to
+            // fill a rect where the dividers would be for non-selectable items
+            // If the list is opaque and the background is also opaque, we don't
+            // need to draw anything since the background will do it for us
+            final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
+
+            if (fillForMissingDividers && mDividerPaint == null && mIsCacheColorOpaque) {
                 mDividerPaint = new Paint();
+                mDividerPaint.setColor(getCacheColorHint());
             }
             final Paint paint = mDividerPaint;
 
@@ -2874,7 +2880,7 @@
                                 bounds.top = bottom;
                                 bounds.bottom = bottom + dividerHeight;
                                 drawDivider(canvas, bounds, i);
-                            } else if (isOpaque) {
+                            } else if (fillForMissingDividers) {
                                 bounds.top = bottom;
                                 bounds.bottom = bottom + dividerHeight;
                                 canvas.drawRect(bounds, paint);
@@ -2903,7 +2909,7 @@
                                 // position. Give -1 when there is no child above the
                                 // divider.
                                 drawDivider(canvas, bounds, i - 1);
-                            } else if (isOpaque) {
+                            } else if (fillForMissingDividers) {
                                 bounds.top = top - dividerHeight;
                                 bounds.bottom = top;
                                 canvas.drawRect(bounds, paint);
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index dc2c70d..5bf8035 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -87,8 +87,9 @@
 
 
     /**
-      * <p>Call setup() before adding tabs if loading TabHost using findViewById(). <i><b>However</i></b>: You do
-      * not need to call setup() after getTabHost() in {@link android.app.TabActivity TabActivity}.
+      * <p>Call setup() before adding tabs if loading TabHost using findViewById().
+      * <i><b>However</i></b>: You do not need to call setup() after getTabHost()
+      * in {@link android.app.TabActivity TabActivity}.
       * Example:</p>
 <pre>mTabHost = (TabHost)findViewById(R.id.tabhost);
 mTabHost.setup();
@@ -363,14 +364,14 @@
          * 
          * @param tag
          *            Which tab was selected.
-         * @return The view to distplay the contents of the selected tab.
+         * @return The view to display the contents of the selected tab.
          */
         View createTabContent(String tag);
     }
 
 
     /**
-     * A tab has a tab indictor, content, and a tag that is used to keep
+     * A tab has a tab indicator, content, and a tag that is used to keep
      * track of it.  This builder helps choose among these options.
      *
      * For the tab indicator, your choices are:
@@ -607,7 +608,7 @@
             }
             mLaunchedView = wd;
             
-            // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activies for now so they can get
+            // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get
             // focus if none of their children have it. They need focus to be able to
             // display menu items.
             //
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index d9fb78b..bae4dad 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -81,27 +81,27 @@
     private static final int ZOOM_CONTROLS_TOUCH_PADDING = 20;
     private int mTouchPaddingScaledSq;
 
-    private Context mContext;
-    private WindowManager mWindowManager;
+    private final Context mContext;
+    private final WindowManager mWindowManager;
     private boolean mAutoDismissControls = true;
 
     /**
      * The view that is being zoomed by this zoom controller.
      */
-    private View mOwnerView;
+    private final View mOwnerView;
 
     /**
      * The location of the owner view on the screen. This is recalculated
      * each time the zoom controller is shown.
      */
-    private int[] mOwnerViewRawLocation = new int[2];
+    private final int[] mOwnerViewRawLocation = new int[2];
 
     /**
      * The container that is added as a window.
      */
-    private FrameLayout mContainer;
+    private final FrameLayout mContainer;
     private LayoutParams mContainerLayoutParams;
-    private int[] mContainerRawLocation = new int[2];
+    private final int[] mContainerRawLocation = new int[2];
 
     private ZoomControls mControls;
 
@@ -113,7 +113,7 @@
     /**
      * The {@link #mTouchTargetView}'s location in window, set on touch down.
      */
-    private int[] mTouchTargetWindowLocation = new int[2];
+    private final int[] mTouchTargetWindowLocation = new int[2];
 
     /**
      * If the zoom controller is dismissed but the user is still in a touch
@@ -128,8 +128,8 @@
     /** Whether the container has been added to the window manager. */
     private boolean mIsVisible;
 
-    private Rect mTempRect = new Rect();
-    private int[] mTempIntArray = new int[2];
+    private final Rect mTempRect = new Rect();
+    private final int[] mTempIntArray = new int[2];
 
     private OnZoomListener mCallback;
 
@@ -141,13 +141,13 @@
      */
     private Runnable mPostedVisibleInitializer;
 
-    private IntentFilter mConfigurationChangedFilter =
+    private final IntentFilter mConfigurationChangedFilter =
             new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
 
     /**
      * Needed to reposition the zoom controls after configuration changes.
      */
-    private BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (!mIsVisible) return;
@@ -167,7 +167,7 @@
      */
     private static final int MSG_POST_SET_VISIBLE = 4;
 
-    private Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -444,6 +444,9 @@
     }
 
     private void refreshPositioningVariables() {
+        // if the mOwnerView is detached from window then skip.
+        if (mOwnerView.getWindowToken() == null) return;
+
         // Position the zoom controls on the bottom of the owner view.
         int ownerHeight = mOwnerView.getHeight();
         int ownerWidth = mOwnerView.getWidth();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a448ac6..51f3b02 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -53,7 +53,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 36;
+    private static final int VERSION = 37;
 
     private final File mFile;
     private final File mBackupFile;
@@ -3014,6 +3014,8 @@
             
             u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
             u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+            u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+            u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
             u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
             u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
 
diff --git a/core/java/com/google/android/util/GoogleWebContentHelper.java b/core/java/com/google/android/util/GoogleWebContentHelper.java
index 2911420..3cdf855 100644
--- a/core/java/com/google/android/util/GoogleWebContentHelper.java
+++ b/core/java/com/google/android/util/GoogleWebContentHelper.java
@@ -130,7 +130,14 @@
         mWebView.loadUrl(mSecureUrl);
         return this;
     }
-    
+
+    public GoogleWebContentHelper loadDataWithFailUrl(String base, String data, 
+        String mimeType, String encoding, String failUrl) {
+        ensureViews();
+        mWebView.loadDataWithBaseURL(base, data, mimeType, encoding, failUrl);
+        return this;
+    }
+
     /**
      * Helper to handle the back key. Returns true if the back key was handled, 
      * otherwise returns false.
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index edf7dc4..6c16150 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -26,7 +26,7 @@
 
 namespace android {
 
-static jint android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)
+static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)
 {
     const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);
 
@@ -37,37 +37,52 @@
     if (name)
         env->ReleaseStringUTFChars(name, namestr);
 
-    if (result < 0)
+    if (result < 0) {
         jniThrowException(env, "java/io/IOException", "ashmem_create_region failed");
-    return result;
+	return NULL;
+    }
+
+    return jniCreateFileDescriptor(env, result);
 }
 
-static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jint fd, jint length)
+static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,
+        jint length)
 {
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     jint result = (jint)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
     if (!result)
         jniThrowException(env, "java/io/IOException", "mmap failed");
     return result;
 }
 
-static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jint fd)
+static void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jint addr, jint length)
 {
-    close(fd);
+    int result = munmap((void *)addr, length);
+    if (result < 0)
+        jniThrowException(env, "java/io/IOException", "munmap failed");
+}
+
+static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor)
+{
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd >= 0) {
+        jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
+        close(fd);
+    }
 }
 
 static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,
-        jint fd, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
+        jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
         jint count, jboolean unpinned)
 {
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
         ashmem_unpin_region(fd, 0, 0);
         jniThrowException(env, "java/io/IOException", "ashmem region was purged");
         return -1;
     }
 
-    jbyte* bytes = env->GetByteArrayElements(buffer, 0);
-    memcpy(bytes + destOffset, (const char *)address + srcOffset, count);
-    env->ReleaseByteArrayElements(buffer, bytes, 0);
+    env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset);
 
     if (unpinned) {
         ashmem_unpin_region(fd, 0, 0);
@@ -76,18 +91,17 @@
 }
 
 static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz,
-        jint fd, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
+        jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
         jint count, jboolean unpinned)
 {
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
         ashmem_unpin_region(fd, 0, 0);
         jniThrowException(env, "java/io/IOException", "ashmem region was purged");
         return -1;
     }
 
-    jbyte* bytes = env->GetByteArrayElements(buffer, 0);
-    memcpy((char *)address + destOffset, bytes + srcOffset, count);
-    env->ReleaseByteArrayElements(buffer, bytes, 0);
+    env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);
 
     if (unpinned) {
         ashmem_unpin_region(fd, 0, 0);
@@ -95,8 +109,9 @@
     return count;
 }
 
-static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jint fd, jboolean pin)
+static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor, jboolean pin)
 {
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     int result = (pin ? ashmem_pin_region(fd, 0, 0) : ashmem_unpin_region(fd, 0, 0));
     if (result < 0) {
         jniThrowException(env, "java/io/IOException", NULL);
@@ -104,12 +119,13 @@
 }
 
 static const JNINativeMethod methods[] = {
-	{"native_open",  "(Ljava/lang/String;I)I", (void*)android_os_MemoryFile_open},
-    {"native_mmap",  "(II)I", (void*)android_os_MemoryFile_mmap},
-    {"native_close", "(I)V", (void*)android_os_MemoryFile_close},
-    {"native_read",  "(II[BIIIZ)I", (void*)android_os_MemoryFile_read},
-    {"native_write", "(II[BIIIZ)V", (void*)android_os_MemoryFile_write},
-    {"native_pin",   "(IZ)V", (void*)android_os_MemoryFile_pin},
+    {"native_open",  "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_MemoryFile_open},
+    {"native_mmap",  "(Ljava/io/FileDescriptor;I)I", (void*)android_os_MemoryFile_mmap},
+    {"native_munmap", "(II)V", (void*)android_os_MemoryFile_munmap},
+    {"native_close", "(Ljava/io/FileDescriptor;)V", (void*)android_os_MemoryFile_close},
+    {"native_read",  "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read},
+    {"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write},
+    {"native_pin",   "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
 };
 
 static const char* const kClassPathName = "android/os/MemoryFile";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fbaef5f..20cb34a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -382,8 +382,8 @@
         android:label="@string/permgrouplab_storage"
         android:description="@string/permgroupdesc_storage" />
 
-    <!-- Allows an application to write to the SD card -->
-    <permission android:name="android.permission.WRITE_SDCARD"
+    <!-- Allows an application to write to external storage -->
+    <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardWrite"
         android:description="@string/permdesc_sdcardWrite"
@@ -644,6 +644,13 @@
         android:description="@string/permdesc_changeWifiState"
         android:label="@string/permlab_changeWifiState" />
 
+    <!-- Allows applications to enter Wi-Fi Multicast mode -->
+    <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:description="@string/permdesc_changeWifiMulticastState"
+        android:label="@string/permlab_changeWifiMulticastState" />
+
     <!-- Allows applications to discover and pair bluetooth devices -->
     <permission android:name="android.permission.BLUETOOTH_ADMIN"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -965,6 +972,13 @@
         android:description="@string/permdesc_batteryStats"
         android:protectionLevel="normal" />
 
+    <!-- Allows an application to control the backup and restore process
+         @hide pending API council -->
+    <permission android:name="android.permission.BACKUP"
+        android:label="@string/permlab_backup"
+        android:description="@string/permdesc_backup"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to tell the AppWidget service which application
          can access AppWidget's data.  The normal user flow is that a user
          picks an AppWidget to go into a particular host, thereby giving that
diff --git a/core/res/res/drawable/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable/stat_sys_vp_phone_call_bluetooth.png
new file mode 100644
index 0000000..7abfd19
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_vp_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/raw/latin_lowercase b/core/res/res/raw/latin_lowercase
index 17cfaf0..443d5f8 100644
--- a/core/res/res/raw/latin_lowercase
+++ b/core/res/res/raw/latin_lowercase
Binary files differ
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7b48267..817a566 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -570,6 +570,15 @@
     <!-- Application's requirement for five way navigation -->
     <attr name="reqFiveWayNav" format="boolean" />
 
+    <!-- The name of the class implementing <code>BackupAgent</code> to manage
+         backup and restore of the application's settings to external storage. -->
+    <attr name="backupAgent" format="string" />
+
+    <!-- Whether the application allows its data to be backed up at all.  This
+         attribute defaults to 'true':  unless the application opts out, the
+         user will be able to back up its data to desktop storage. -->
+    <attr name="allowBackup" format="boolean" />
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -643,6 +652,8 @@
         <attr name="manageSpaceActivity" />
         <attr name="allowClearUserData" />
         <attr name="testOnly" />
+        <attr name="backupAgent" />
+        <attr name="allowBackup" />
     </declare-styleable>
     
     <!-- The <code>permission</code> tag declares a security permission that can be
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 621270e..c2c84d6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1113,7 +1113,9 @@
   <public type="attr" name="gestureStrokeAngleThreshold" />
   <public type="attr" name="eventsInterceptionEnabled" />
   <public type="attr" name="fadeEnabled" />
-
+  <public type="attr" name="backupAgent" />
+  <public type="attr" name="allowBackup" />
+  
   <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 8b2689bd..e048ffe 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -148,6 +148,24 @@
     <!-- Meaning: unknown.  Example: Service was enabled for: Voice, PAD -->
     <string name="serviceClassPAD">PAD</string>
 
+    <!-- CDMA Roaming Indicator Strings (non ERI)--> <skip />
+    <!-- Default roaming indicator text -->
+    <string name="roamingText0">Roaming Indicator On</string>
+    <string name="roamingText1">Roaming Indicator Off</string>
+    <string name="roamingText2">Roaming Indicator Flashing</string>
+    <string name="roamingText3">Out of Neighborhood</string>
+    <string name="roamingText4">Out of Building</string>
+    <string name="roamingText5">Roaming - Preferred System</string>
+    <string name="roamingText6">Roaming - Available System</string>
+    <string name="roamingText7">Roaming - Alliance Partner</string>
+    <string name="roamingText8">Roaming - Premium Partner</string>
+    <string name="roamingText9">Roaming - Full Service Functionality</string>
+    <string name="roamingText10">Roaming - Partial Service Functionality</string>
+    <string name="roamingText11">Roaming Banner On</string>
+    <string name="roamingText12">Roaming Banner Off</string>
+    <string name="roamingTextSearching">Searching for Service</string>
+
+
     <!--
         {0} is one of "bearerServiceCode*"
         {1} is dialing number
@@ -540,6 +558,11 @@
         collected battery statistics. Not for use by normal applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_backup">control system backup and restore</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_backup">Allows the application to control the system's backup and restore mechanism.  Not for use by normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_internalSystemWindow">display unauthorized windows</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_internalSystemWindow">Allows the creation of
@@ -1005,6 +1028,15 @@
       configured Wi-Fi networks.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_changeWifiMulticastState">allow Wi-Fi Multicast
+      reception</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_changeWifiMulticastState">Allows an application to
+      receive packets not directly addressed to your device.  This can be
+      useful when discovering services offered near by.  It uses more power
+      than the non-multicast mode.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetoothAdmin">bluetooth administration</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin">Allows an application to configure
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 490abde..72402d0 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -177,7 +177,7 @@
         <item name="android:uncertainGestureColor">#48ffff00</item>
         <item name="android:fadeOffset">420</item>
         <item name="android:fadeDuration">150</item>
-        <item name="android:gestureStrokeLengthThreshold">30.0</item>
+        <item name="android:gestureStrokeLengthThreshold">50.0</item>
         <item name="android:gestureStrokeSquarenessThreshold">0.275</item>
         <item name="android:gestureStrokeAngleThreshold">40.0</item>
         <item name="android:eventsInterceptionEnabled">true</item>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 33d6b3b..0bd3276 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -54,7 +54,7 @@
         <group gid="log" />
     </permission>
 
-    <permission name="android.permission.WRITE_SDCARD" >
+    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
         <group gid="sdcard_rw" />
     </permission>
 
@@ -85,7 +85,7 @@
          interact with the system. -->
 
     <!-- Standard permissions granted to the shell. -->
-    <assign-permission name="android.permission.WRITE_SDCARD" uid="shell" />
+    <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
     <assign-permission name="android.permission.SEND_SMS" uid="shell" />
     <assign-permission name="android.permission.CALL_PHONE" uid="shell" />
     <assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index da5192a..da4a2c3 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -148,6 +148,7 @@
           <ul>
             <li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design.html">Icon Design</a></li>
             <li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/widget_design.html">App Widget Design</a></li>
+            <li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/activity_task_design.html">Activity and Task Design</a></li>
           </ul>
       </li>
       <li><a href="<?cs var:toroot ?>guide/practices/design/performance.html">Designing for Performance</a></li>
diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
new file mode 100644
index 0000000..bec0e43
--- /dev/null
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -0,0 +1,1223 @@
+page.title=Activity and Task Design Guidelines
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Activity and task design quickview</h2>
+
+<ul>
+<li>Activities are the main building blocks of Android applications. </li>
+<li>In addition to writing your own activities, you are free to re-use activities from many other applications through intents.</li>
+<li>You can enable activities in your application to be started from intents in other applications.</li>
+<li>In nearly all cases, the activity stack just works as expected.</li>
+    In a couple of cases you might need to ensure the right thing happens by setting a string or flag.</li>
+</ul>
+
+<h2>In this document</h2>
+
+<ol>
+  <li><a href=#applications_activities>Applications, Activities, Activity Stack and Tasks</a>
+  </li>
+  <li><a href=#tour>A Tour of Activities and Tasks
+    <ol>
+      <li><a href=#starting_an_activity_from_home>Starting an Activity from Home</a></li>
+      <li><a href=#navigating_away_from_an_activity>Navigating Away from an Activity</a></li>
+      <li><a href=#reusing_an_activity>Re-using an Activity</a></li>
+      <li><a href=#replacing_an_activity>Replacing an Activity</a></li>
+      <li><a href=#multitasking>Multitasking</a></li>
+      <li><a href=#launching_from_two_entry_points>Launching from Two Entry Points</a></li>
+      <li><a href=#intents>Intents</a></li>
+      <li><a href=#switching_between_tasks>Switching Between Tasks</a></li>
+    </ol>
+  </li>
+  <li><a href=#tips>Design Tips
+    <ol>
+      <li><a href=#activity_not_reused_tip>Don't specify intent filters in an activity that won't be re-used</a></li>
+      <li><a href=#others_to_reuse_tip>Don't define your own URI schemes</a></li>
+      <li><a href=#reusing_tip>Handle where a re-used activity is missing</a></li>
+      <li><a href=#activity_launching_tip>Consider how to launch your activities</a></li>
+      <li><a href=#activities_added_to_task_tip>Allow activities to add to current task</a></li>
+      <li><a href=#notifications_return_tip>Notifications should be easy to return from</a></li>
+      <li><a href=#use_notification_tip>Use the notification system</a></li>
+      <li><a href=#taking_over_back_key>Don't take over BACK key unless you absolutely need to</a></li>
+    </ol>
+  </li>
+</ol>
+
+<h2>See also</h2>
+
+<ol>
+  <li><a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a></li>
+  <li><a href="http://android-developers.blogspot.com/2009/05/activities-and-tasks.html">Activities and Tasks blog post</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>
+  This document describes core principles of the Android application
+  framework, from a high-level, user-centric perspective useful to
+  interaction and application designers as well as application
+  developers.
+</p>
+
+<p>
+  It illustrates activities and tasks with examples, and describes some
+  of their underlying principles and mechanisms, such as navigation,
+  multitasking, activity re-use, intents, and the activity stack. 
+  The document also highlights design decisions that are available to you
+  and what control they give you over the UI of your application.
+</p>
+
+<p>
+  This document draws examples from several Android applications,
+  including default applications (such as Dialer) and Google
+  applications (such as Maps).  You can try out the examples yourself in
+  the Android emulator or on an Android-powered device. If you are using
+  a device, note that your device may not offer all of the example
+  applications used in this document.
+</p>
+
+<p>
+  Be sure to look at the <a href="#design_tips">Design Tips</a> section
+  for guidelines, tips, and things to avoid. This document is a
+  complement to <a href={@docRoot}guide/topics/fundamentals.html
+  title="Application Fundamentals">Application Fundamentals</a>, 
+  which covers the underlying mechanics for programmers.
+</p>
+
+<h2 id="applications_activities">Applications, Activities, Activity Stack and Tasks</h2>
+
+<p>
+  Four fundamental concepts in the Android system that are helpful for you to understand are:
+</p>
+
+<ul>
+  <li>Applications
+  <li>Activities
+  <li>Activity Stack
+  <li>Tasks
+</ul>
+
+<h3 id=applications>Applications</h3>
+
+<p>
+  An Android <em>application</em> typically consists of one or more
+  related, loosely bound activities <!--(and possibly 
+  <a href=#services_broadcast_receivers title="other components">other
+  components</a>)--> for the user to interact with, typically bundled up
+  in a single file (with an .apk suffix). Android ships with a rich set
+  of applications that may include email, calendar, browser, maps, text
+  messaging, contacts, camera, dialer, music player, settings and
+  others.
+</p>
+
+<p>
+  Android has an application launcher available at the Home screen,
+  typically in a sliding drawer which displays applications as icons,
+  which the user can pick to start an application.
+</p>
+
+
+<h3 id=activities>Activities</h3>
+
+<p>
+  <em>Activities</em> are the main building blocks of Android
+  applications. When you create an application, you can assemble it from
+  activities that you create and from activities you re-use from other
+  applications. These activities are bound at runtime, so that newly
+  installed applications can take advantage of already installed
+  activities.  Once assembled, activities work together to form a
+  cohesive user interface. An activity has a distinct visual user
+  interface designed around a single, well-bounded purpose, such as
+  viewing, editing, dialing the phone, taking a photo, searching,
+  sending data, starting a voice command, or performing some other type
+  of user action. Any application that presents anything on the display
+  must have at least one activity responsible for that display.
+</p>
+
+<p>
+  When using an Android device, as the user moves through the user
+  interface they start activities one after the other, totally oblivious
+  to the underlying behavior &mdash; to them the experience should be
+  seamless, activity after activity, <a href="#tasks">task</a> after
+  task.
+</p>
+  
+<p>
+  An activity handles a particular type of content (data) and accepts a
+  set of related user actions. In general, each activity has a 
+  <a href={@docRoot}guide/topics/fundamentals.html#actlife
+  title=lifecycle>lifecycle</a> that is independent of the other
+  activities in its application or task &mdash; each activity is
+  launched (started) independently, and the user or system can start,
+  run, pause, resume, stop and restart it as needed. Because of this
+  independence, activities can be re-used and replaced by other
+  activities in a variety of ways.
+</p>
+
+<p>
+  The Dialer application is an example of an application that consists
+  basically of four activities: dialer, contacts list, view contact, and
+  new contact, as shown in the following screenshots:
+</p>
+
+      <table style="border: none;">
+        <tbody>
+        <tr>
+          <td style="border: none !important;">
+            <img src={@docRoot}images/activity_task_design/ContactsDialer.png>
+            <div style=TEXT-ALIGN:center>
+              Dialer
+            </div>
+          </td>
+          <td style="border: none !important;">
+            <img src={@docRoot}images/activity_task_design/ContactsList.png>
+            <div style=TEXT-ALIGN:center>
+              Contacts
+            </div>
+          </td>
+          <td style="border: none !important;">
+            <img src={@docRoot}images/activity_task_design/ContactView.png>
+            <div style=TEXT-ALIGN:center>
+              View Contact
+            </div>
+          </td>
+          <td style="border: none !important;">
+            <img src={@docRoot}images/activity_task_design/ContactNew.png>
+            <div style=TEXT-ALIGN:center>
+               New Contact
+            </div>
+          </td>
+        </tr>
+        </tbody>
+      </table>
+
+<p>
+  Here are other examples of applications and the activities they might contain:
+</p>
+
+    <ul>
+      <li>
+        Email - activities to view folders, view list of messages,
+        view a message, compose a message, and set up an account
+      </li>
+      <li>
+        Calendar - activities to view day, view week, view month, view
+        agenda, edit an event, edit preferences, and view an alert
+      </li>
+      <li>
+        Camera - activities for running the camera, viewing the list
+        of pictures, viewing a picture, cropping a picture, running
+        the camcorder, viewing the list of movies, and viewing a movie
+      </li>
+      <li>
+        Game - one activity to play the game, typically another for setup
+      </li>
+      <li>
+        Maps - one activity to view a location on a map, a second for lists
+        (such as turn list or friend list), and a third for details
+        (friend location, status, photo)
+      </li>
+    </ul>
+
+
+<p>
+  An activity is the most prominent of four <em>components</em> of an
+  application. The other components are service, content provider and
+  broadcast receiver. For more details on activities, see Activity in
+  <a href={@docRoot}guide/topics/fundamentals.html#appcomp
+  title="Application Components">Application Components</a>.
+</p>
+
+
+<h3 id="activity_stack">Activity Stack</h3>
+
+<p>
+  As the user moves from activity to activity, across applications, the
+  Android system keeps a linear navigation history of activities the
+  user has visited. This is the <em>activity stack</em>, also known as the
+  back stack. In general, when a user starts a new activity, it is added
+  to the activity stack, so that pressing BACK displays the previous
+  activity on the stack. However, the user cannot use the BACK key to go
+  back further than the last visit to Home. The adding of an activity to
+  the current stack happens whether or not that activity begins a new 
+  <a href=#tasks title=task>task</a> (as long as that task was started
+  without going Home), so going back can let the user go back to
+  activities in previous tasks. The user can get to tasks earlier than
+  the most recent Home by selecting its root activity from the
+  application launcher, a shortcut, or the "Recent tasks" screen.
+</p>
+
+<p>
+  Activities are the only things that can be added to the activity stack
+  &mdash; views, windows, menus, and dialogs cannot. That is, when
+  designing the navigation, if you have screen A and you want the user
+  to be able go to a subsequent screen B and then use the BACK key to go
+  back to screen A, then the screen A needs to be implemented as an
+  activity. The one exception to this rule is if your application 
+  <a href=#taking_over_back_key title="takes control of the BACK key"
+  takes control of the BACK key</a> and manages the navigation itself.
+</p>
+
+
+
+<h3 id=tasks>Tasks</h3>
+
+<p>
+  A <em>task</em> is the sequence of activities the user follows to
+  accomplish an objective, regardless of which applications the
+  activities belong to. Until a new task is explicitly specified (see
+  "Interrupting the Task"), all activities the user starts are
+  considered to be part of the current task. It's notable that these
+  activities can be in any application &mdash; that is, all in the same
+  application or in different ones. That is, a task that starts out in
+  contacts can continue, by choosing an email address, to an email
+  activity and then, by attaching a file, to a picture gallery to pick
+  from. Contacts, email and picture gallery are all separate
+  applications.
+</p>
+
+<p>
+  The activity that starts a task is called the <em>root activity</em>.
+  It is often, but not necessarily, started from the application
+  launcher, Home screen shortcut or "Recent tasks" switcher (a long
+  press on Home on some devices). The user can return to a task by
+  choosing the icon for its root activity the same way they started the
+  task. Once inside a task, the BACK key goes to previous activities in
+  that task. The activity stack is made up of one or more tasks.
+</p>
+
+<p>
+  Here are some examples of tasks:
+</p>
+
+    <ul>
+      <li>
+        Send a text message with an attachment
+      </li>
+      <li>
+        View a YouTube video and share it by email with someone else 
+      </li>
+    </ul>
+
+<p>
+  <b>Interrupting the Task</b> - An important property of a task is that
+  the user can interrupt what they're doing (their task) to perform a
+  different task, then are able to return to where they left off to
+  complete the original task. The idea is that users can run multiple
+  tasks simultaneously and switch between them. There are two primary
+  ways to jump off to that other task &mdash; in both cases the user
+  should be able to return to where they were before the interruption:
+</p>
+
+
+  <ul>
+    <li>
+      User is interrupted by a notification – a notification appears and the user wants to act on it
+    </li>
+    <li>
+      User deciding to perform another task – user just presses Home and starts an application
+    </li>
+  </ul>
+
+<p>
+  Of course, there are exceptions to the rules. Beyond the two ways just
+  mentioned, there is a third way to start a task, and that is by
+  starting an activity that defines itself as a new task. Maps and
+  Browser are two applications that do this. For example, choosing an
+  address in an email starts the Maps activity as a new task, and
+  choosing a link in an email starts the Browser activity as a new
+  task. In these cases, the BACK key will return to the previous
+  activity in a different task (Email), because it was not started from
+  Home.
+</p>
+
+
+<h2 id="tour">A Tour of Activities and Tasks</h2>
+
+<p>
+  The following examples illustrate basic principles for applications,
+  activities, the activity stack, the BACK key, tasks and intents.  It
+  shows how the system responds to user actions such as starting
+  activities and switching between tasks.  With most of these examples
+  you can follow along, launching activities on your device as
+  indicated.
+</p>
+
+
+<h3 id=starting_an_activity_from_home>Starting an Activity from Home</h3>
+
+<p>
+  Home is the starting place for most applications. (Some applications
+  can be launched only from other applications.) When the user touches
+  an icon in the application launcher (or a shortcut on the Home
+  screen), the main activity for that application is launched into the
+  foreground where it has user focus. As shown in the following figure,
+  the user action of going Home and touching the Email icon launches the
+  List Messages activity of the Email application. The Home activity
+  remains stopped in the background, ready to restart when called on by
+  the user.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/HomeTaskBasics1a.png>
+</p>
+
+<h3 id=navigating_away_from_an_activity>Navigating Away from an Activity with BACK and HOME keys</h3>
+
+<p>
+  An activity can keep or lose its state depending on how the user
+  leaves the activity &mdash; by the HOME or BACK key.
+</p>
+
+<p>
+  By default, pressing the BACK key finishes (destroys) the current
+  activity and displays the previous activity to the user. In the
+  following figure, the user starts email by touching the Email icon in
+  the Home screen, which displays a list of email messages. The user
+  scrolls down the list (changing its initial state). Pressing BACK
+  destroys the List Messages activity and returns to the previous
+  activity, which is Home. If the user re-launches Email, it would
+  re-load the messages and display its initial, non-scrolled state.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/HomeTaskBasics1b.png>
+</p>
+
+<p>
+  In the above example, pressing BACK goes to Home because it was the
+  last activity the user was viewing. But if the user had gotten to List
+  Message from some other activity, then pressing BACK would have
+  returned there.
+</p>
+
+<p>
+  By contrast, the next figure shows the user leaving List Messages by
+  pressing HOME instead of BACK &mdash; the List Messages activity is
+  stopped and moved to the background rather than being
+  destroyed. Starting Email again from its icon would simply bring the
+  List Messages activity to the foreground (changing it from stopped to
+  running) in the same scrolled state the user last left it.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/HomeTaskBasics1c.png>
+</p>
+
+<p>
+  <b>Exceptions.</b> Some background activities return to their initial
+  screen (they lose any state, such as scrolling) when they are brought
+  to the foreground. This is true for Contacts and Gallery. If the user
+  chooses Home &gt; Contacts then chooses a contact, they are viewing
+  the details of a contact. If they start again by choosing Home &gt;
+  Contacts, they are presented with the initial list of contacts rather
+  than the contact they were last viewing. Contacts is designed this way
+  because this initial screen is the main entry point for the
+  application with four tabs for accessing the full range of features.
+</p>
+
+<p>
+  In addition, not all activities have the behavior that they are
+  destroyed when BACK is pressed. When the user starts playing music in
+  the Music application and then presses BACK, the application overrides
+  the normal back behavior, preventing the player activity from being
+  destroyed, and continues playing music, even though its activity is no
+  longer visible &mdash; as a visual substitute, the Music application
+  places a notification in the status bar so the user still has an easy
+  way to get to the application to stop or control the music. Note that
+  you can write an activity to stop when its screen is no longer
+  visible, or to continue running in the background &mdash; the latter
+  was chosen for the music player.
+</p>
+
+
+<h3 id=reusing_an_activity>Re-using an Activity</h3>
+
+<p>
+  When activity A starts activity B in a different application, activity
+  B is said to be <em>re-used</em>. This use case normally takes place
+  because activity A is lacking a capability and can find it in activity B.
+</p>
+
+<p>
+  <b>Contacts Re-Uses Gallery to Get a Picture</b> - The Contacts
+  activity has a field for a picture of a contact, but the Gallery is
+  normally where pictures are kept. So Contacts can re-use the Gallery
+  activity to get a picture. This is a good example of re-use of the
+  Gallery activity. The following figure illustrates the sequence of
+  activities to do this (up to crop). This is how it's done: The user
+  chooses Contacts, selects the contact for viewing, chooses MENU &gt;
+  Edit contact and touches the picture field, which launches the Gallery
+  activity. The user then chooses the picture they want, crops and saves
+  it. Saving it causes the picture to be inserted into the picture field
+  in the contact.
+</p>
+
+<p>
+  Notice the Gallery returns a picture to the Contacts application that
+  started it. The next example illustrates re-use of an activity that
+  does not return a result. Also notice that the following figure is
+  illustrates the navigation history through the activities, or the
+  activity stack &mdash; the user can back up through each activity all
+  the way to Home.
+</p>
+
+<p>
+  When designing an application, it's good to think about how it can
+  re-use activities in other applications, and how your activities might
+  be re-used by other applications. If you add an activity with the same
+  <a href=#intents title="intent filter">intent filter</a> as an
+  exisiting activity, then the system presents the user with a choice
+  between the activities.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/ReusingAnActivity1.png>
+</p>
+
+<p>
+  <b>Gallery Re-Uses Messaging for Sharing a Picture</b> - Sharing is
+  another good example of one application re-using an activity from a
+  different application. As shown in the following figure, the user
+  starts Gallery, picks a picture to view, chooses MENU &gt; Share, and
+  picks "Messaging". This starts the Messaging activity, creates a new
+  message and attaches the original picture to it. The user then fills
+  in the "To" field, writes a short message and sends it. User focus
+  remains in the Messaging program. If the user wants to go back to the
+  Gallery, they must press the BACK key. (The user can back up through
+  each activity all the way to Home.)
+</p>
+
+<p>
+  In contrast to the previous example, this re-use of the Messaging
+  activity does not return anything to the Gallery activity that started it.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/ReusingAnActivity2.png>
+</p>
+
+<p>
+  Both of these examples illustrate tasks &mdash; a sequence of
+  activities that accomplish an objective. Each case uses activities
+  from two different applications to get the job done.
+</p>
+
+
+<h3 id=replacing_an_activity>Replacing an Activity</h3>
+
+<p>
+  This is the use case where activity A replaces activity B in a
+  different application. This situation normally happens because
+  activity A is better at doing the job than activity B. In other words,
+  A and B are equivalent enough that A can replace B. This case stands
+  in contrast with re-using an activity, where A and B are quite
+  different activities and supplement each other.
+</p>
+
+<p>
+  In this example, the user has downloaded a replacement for the Phone
+  Ringtone activity, called Rings Extended. Now when they go to
+  Settings, Sound &amp; Display, Phone Ringtone, the system presents
+  them with a choice between the Android System's ringtone activity and
+  the new one. This dialog box has an option to remember their choice
+  "Use by default for this action". When they choose "Rings Extended",
+  that activity loads, replacing the original Android ringtone activity.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/ReplacingAnActivity.png>
+</p>
+
+<h3 id=multitasking>Multitasking</h3>
+
+<p>
+  As previously noted, when an activity has been launched, the user can
+  go to Home and launch a second activity without destroying the first
+  activity. This scenario demonstrates launching the Maps application.
+</p>
+
+  <ul>
+    <li>
+      State 1 - The user launches the View Map activity and searches
+      for a map location. Let's say the network is slow, so the map is
+      taking an unusually long taking time to draw.
+    </li>
+  </ul>
+  <ul>
+    <li>
+      State 2 - The user wants to do something else while they're
+      waiting, so they press HOME, which does not interrupt the map's
+      network connection and allows the map to continue loading in the
+      background.
+
+      <p>
+      Note that when you write an activity, you can make it stop or
+      continue running when it is moved to the background (see
+      onStop() in <a href={@docRoot}guide/topics/fundamentals.html#actlife
+      title="Activity Lifecycle">Activity Lifecycle</a>).
+      For activities that download data from the network, it's recommended
+      to let them continue downloading so the user can multi-task.
+      </p>
+
+    </li>
+
+    <li>
+      State 3 - The map activity is now running in the background,
+      with Home in the foreground. The user then launches the Calendar
+      activity, which launches into the foreground, taking user focus,
+      where they view today's calendar (as indicated by the heavy
+      outline).
+    </li>
+  </ul>
+
+<p>
+<img src={@docRoot}images/activity_task_design/HomeTaskBasics1d.png>
+</p>
+      <ul>
+        <li>
+          State 4 - The user presses Home, then Maps to return to the map, which by now has fully loaded.
+        </li>
+      </ul>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/HomeTaskBasics1e.png>
+</p>
+
+<p>
+  The application launcher at Home has launched "View Map" and "Day
+  View" activities into separate <em>tasks</em>, hence the system is
+  multitasking &mdash; running multiple <a href=#tasks
+  title=tasks>tasks</a>.
+</p>
+
+
+<h3 id=launching_from_two_entry_points>Launching from Two Entry Points</h3>
+
+<p>
+  Every application must have at least one entry point &mdash; a way
+  for the user or system to access activities inside the
+  application. Each icon in the application launcher at home
+  represents an entry point. Applications can also from another
+  application. Each activity is a potential entry point into the
+  application.&nbsp;
+</p>
+
+<p>
+  The phone application has two entry points: Contacts and Dialer. A
+  user entering from Contacts can choose a phone number to launch the
+  Dialer. As shown in the following figure, a user could choose the
+  Contacts icon to launch the Contacts activity, then pick a phone
+  number to launch the Dialer activity and dial the phone.
+</p>
+
+<p>
+  Once the user is inside the application, they can access other
+  activities, such as New Contact and Edit Contact, through tabs, menu
+  items, list items, onscreen buttons, or other user interface
+  controls.
+</p>
+
+<p>
+<img src={@docRoot}images/activity_task_design/PhoneActivitiesDiagram.png>
+</p>
+
+<h3 id=intents>Intents</h3>
+
+<p>
+  When the user takes an action on some data, such as touching a
+  mailto:info@example.com link, they are actually initiating an Intent
+  object which then gets resolved to a particular component (we will
+  consider only activity components here). So, the result of a user
+  touching a mailto: link is an Intent object that the system tries to
+  match to an activity. If that Intent object was written explicitly
+  naming an activity (an <em>explicit intent</em>), then the system
+  immediately launches that activity in response to the user
+  action. However, if that Intent object was written without naming an
+  activity (an <em>implicit intent</em>), the system compares the Intent
+  object to the <em>intent filters</em> of available activities. If more
+  than one activity can handle the action and data, the system
+  displays an activity chooser for the user to choose from.
+</p>
+
+<p>
+  This example of touching the mailto: link is shown in the following
+  figure. If the device has two email applications set up, when a user
+  touches a mailto: email address on a web page, the result is an
+  Intent object which displays a dialog box with a choice between the
+  two activities to compose an email (Gmail and Email).
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/IntentsDiagram.png>
+</p>
+
+<p>
+  Here are some examples of Intent objects and the activities they resolve to:
+</p>
+
+  <ul>
+    <li>
+      View the list of contacts - resolves to a contact list viewer activity
+    </li>
+
+    <li>
+      View a particular contact - resolves to a contact viewer activity
+    </li>
+
+    <li>
+      Edit a particular contact - resolves to a contact editor activity
+    </li>
+
+    <li>
+      Send to a particular email - resolves to an email activity
+    </li>
+
+    <li>
+      Dial a phone number - resolves to a phone dialer activity
+    </li>
+
+    <li>
+       View the list of images - resolves to an image list viewer activity
+    </li>
+
+    <li>
+        View a particular image - resolves to an image viewer activity
+    </li>
+
+    <li>
+        Crop a particular image - resolves to an image cropper activity
+    </li>
+  </ul>
+
+<p>
+  Notice that an Intent object specifies two things, an action and data:
+</p>
+
+    <ul>
+      <li>
+        A generic action to be performed. In these examples: view, edit, dial or crop
+      </li>
+
+      <li>
+        The specific data to be acted on. In these examples: the list of contacts, a particular contact, a phone number, the list of images, or a particular image
+      </li>
+    </ul>
+
+    <p>
+      Note that any user action to start an activity from the
+      application launcher at Home is an explicit intent to a specific
+      activity. Likewise, some activities launch private activities
+      within their application as explicit intents so no other activity
+      can access them.
+    </p>
+
+    <p>
+      For more on intents, see {@link android.content.Intent Intent class} and
+      <a href={@docRoot}guide/topics/fundamentals.html#ifilters
+      title="intent filters">intent filters</a>.
+    </p>
+
+
+<h3 id=switching_between_tasks>Switching Between Tasks</h3>
+
+<p>
+  This scenario shows how the user can switch between two tasks. In
+  this example, the user writes a text message, attaches a picture,
+  but before they are done they glance at their calendar. They then
+  return to where they left off, attaching the picture and sending the
+  message.
+</p>
+
+    <ol>
+      <li>
+        <b>Start first task.</b> You want to send a text message and attach a photo. You would choose:
+
+        <p>
+          Home &gt; Messaging &gt; New message &gt; MENU &gt; Attach
+          &gt; Pictures. This last step launches the picture gallery
+          for picking a photo. Notice that picture gallery is an
+          activity in a separate application.
+        </p>
+
+
+        <table>
+          <tbody>
+            <tr>
+            <td valign=top style="border: none !important;">
+              <img src={@docRoot}images/activity_task_design/HomeTaskSwitching1a.png>
+            </td>
+            <td valign=top style="border: none !important;">
+              <img src={@docRoot}images/activity_task_design/HomeTaskSwitching1b.png>
+            </td>
+            <td valign=top style="border: none !important;">
+              <img src={@docRoot}images/activity_task_design/HomeTaskSwitching1c.png>
+            </td>
+            </tr>
+          </tbody>
+        </table>
+
+        <p>
+          At this point, before you have picked a picture, you decide
+          to stop and glance at your calendar, which is a separate
+          task. Because the current activity has no button to go
+          directly to the Calendar, you need to start from Home.
+        </p>
+
+      </li>
+      <li>
+        <b>Start second task.</b> You choose Home &gt; Calendar to
+        look at a calendar event. Calendar launches from Home as a new
+        task because the application launcher creates a new task for
+        each application it launches.
+
+        <p>
+      <img src={@docRoot}images/activity_task_design/HomeTaskSwitching2.png>
+        </p>
+      </li>
+
+      <li>
+        <b>Switch to first task and complete it.</b> When done looking
+        at the Calendar, you can return to attaching the picture by
+        starting the root activity again for that task: choose Home
+        &gt; Messaging, which takes you not to Messaging, but directly
+        to the Picture gallery, where you left off. You can then pick
+        a photo, which is added to the message, you send the message
+        and you're done with the first task.
+
+      <table>
+        <tbody>
+        <tr>
+
+          <td valign=top style="border: none !important;">
+            <img src={@docRoot}images/activity_task_design/HomeTaskSwitching3a.png>
+          </td>
+
+          <td valign=top style="border: none !important;">
+            <img src={@docRoot}images/activity_task_design/HomeTaskSwitching3b.png>
+          </td>
+
+          <td valign=top style="border: none !important;">
+            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src={@docRoot}images/activity_task_design/HomeTaskSwitching3c.png>
+          </td>
+
+        </tr>
+        </tbody>
+      </table>
+      </li>
+    </ol>
+
+
+<h2 id="tips">Design Tips</h2>
+
+<p>
+  The following are tips and guidelines for application designers and developers.
+</p>
+
+<h3 id=activity_not_reused_tip>When writing an activity that won't be re-used, don't specify intent filters &mdash; use explicit intents</h3>
+
+<p>
+  If you're writing an activity that you don't want other activities
+  to use, be sure not to add any intent filters to that activity. This
+  applies to an activity that will be launched only from the
+  application launcher or from other activities inside your
+  application. Instead, just create intents specifying the explicit
+  component to launch &mdash; that is, explicit intents. In this case,
+  there's just no need for intent filters. Intent filters are
+  published to all other applications, so if you make an intent
+  filter, what you're doing is publishing access to your activity,
+  which means you can cause unintentional security holes.
+</p>
+
+<!--
+<h3 id="others_to_reuse_tip">When writing an activity for others to re-use, don't define your own URI schemes</h3>
+
+<p>
+  If publishing to others, don't define your own URI schemes in an
+  Intent type. Schemes (such as http: and mailto:) are an Internet
+  standard with a universal namespace outside of just Android, so you
+  aren't allowed to just make up your own. Instead, you should just
+  define your own actions. The action namespace is designed to not
+  have conflicts. Typically, your activity has one scheme with many
+  different actions.
+</p>
+
+<p>
+  Example: You want to show the user a bar code for some text. The
+  wrong way to do this is for the intent filter protocol to be
+  &lt;action android:name="android.intent.action.VIEW" /&gt; and
+  &lt;data android:scheme="barcode" /&gt;. Do not do this.
+</p>
+
+<p>
+  Instead you should define &lt;action
+  android:name="com.example.action.SHOW_BARCODE" /&gt; and have the
+  invoker supply the data as an extra field in the Intent object.
+</p>
+
+<p>
+  Be aware this intent filter protocol
+  ("com.example.action.SHOW_BARCODE", in this example) is a public API
+  that you can't change once it's defined. You must support it in the
+  future because others are going to be relying on it. If you want to
+  add new features that are incompatible with the current protocol,
+  just define a new protocol and continue to support the old one.
+</p>
+-->
+
+<h3 id="reusing_tip"> When reusing an activity owned by others, handle the case where no activity matches</h3>
+
+<p>
+  Your applications can re-use activities made available from other
+  applications. In doing so, you cannot presume that external activity
+  will always be present &mdash; you must handle the case that the
+  external activity is not installed. Do this in the way you find most
+  appropriate, such as dimming the user control that accesses it (such
+  as a button or menu item), or displaying a message to the user that
+  sends them to the location to download it, such as the Market.
+</p>
+
+<h3 id=activity_launching_tip>Consider how you want your activities to be launched or used by other applications</h3>
+
+<p>
+  As a designer or developer, it's up to you to determine how users
+  start your application and the activities in it. As an application
+  is a set of activities, the user can start these activities from
+  Home or from another application.
+</p>
+
+    <ul>
+      <li>
+        <b>Launch your main activity from an icon at Home </b>- If
+        your application can run standalone, it should probably be
+        started by the user touching an icon in <em>application
+        launcher</em> (typically implemented as a sliding drawer on the
+        Home screen), or from a shortcut icon on the Home screen, or
+        from the task switcher.  (The mechanism for this is for the
+        activity to have an 
+        <a href={@docRoot}guide/topics/fundamentals.html#ifilters
+        title="Intent filter">intent filter</a> with action MAIN and
+        category LAUNCHER.)
+      </li>
+    </ul>
+
+    <ul>
+      <li>
+        <b>Launch your activity from within another application</b> -
+        Perhaps your activities are meant for re-use. For example,
+        many applications have data they want to share with other
+        users. Activities that can share data with other users include
+        email, text messaging and uploading to a public website.  <p>
+        If one or more of your activities can be an alternative to an
+        existing activity in another application, you can make it
+        available to users at the point they request that
+        activity.&nbsp;For example, if your activity can send data to
+        others (such as by email, text messaging, or uploading),
+        consider setting up that activity to appear as a choice to the
+        user. To give a specific example, Gallery enables a user to
+        view and share pictures. When the user chooses "Share" from
+        the menus, the system compares the "Share" request (an Intent
+        object) to available activities (by looking at their intent
+        filters) and displays choices to share. In this case, it
+        matches Email, Gmail, Messaging and Picassa. If your activity
+        can send a picture or upload it to a website, all it needs to
+        do is make itself available for sharing (by setting its intent
+        filter).
+        </p>
+<p>
+  Another activity can start your activity either with or without expecting a result back.&nbsp;
+</p>
+      </li>
+
+      <ul>
+        <li>
+          <b>Start an activity expecting a result</b> - This approach
+          is closed loop, where the activity being started must either
+          return a valid result or be canceled. In the previous
+          examples of sharing a photo from a Gallery, the user ends up
+          back in the Gallery after completing the send or upload
+          procedure. These are examples of starting an activity
+          external to the Gallery. (Such an activity is started with
+          {@link
+          android.app.Activity#startActivityForResult(android.content.Intent,
+          int) startActivityForResult()}.)
+        </li>
+
+        <li>
+          <b>Start an activity not expecting a result</b> - This
+          approach is open-ended. An example is choosing an house
+          address in an email message (or web page), where the Maps
+          activity is started to map the location. No result from maps
+          is expected to be returned to the email message; the user
+          can return by pressing the BACK key. (Such an activity is
+          started with {@link
+          android.content.Context#startActivity(android.content.Intent)
+          startActivity()}.)
+        </li>
+      </ul>
+
+      <li>
+        <b>Launch your activity <em>only</em> from within another
+        application</b> - The previous cases of sharing by way of
+        Email, Gmail, Messaging and Picassa (from within Gallery) are
+        all activities that can also be started from icons in the
+        application launcher at Home. In contrast, the activities for
+        cropping a picture and attaching a file cannot be started from
+        Home, because they do not stand alone and require a
+        context.&nbsp;
+      </li>
+
+<p>
+  In fact, not all applications have icons and can be started from
+  Home. Take for example a small app that is infrequently used and
+  replaces existing functionality, that already has a natural entry
+  point inside an existing application. For example, an Android phone
+  typically has a built-in ringtone picker that can be selected from
+  the sound settings of the Settings application. A custom ringtone
+  picker application that you write could be launched by an intent
+  identical to the built-in ringtone picker. At the point where the
+  user chooses "Phone ringtone", they are presented with a dialog
+  letting them choose between "Android System" and your ringtone
+  picker (and letting them save their choice) as shown in the
+  following figure. A ringtone is something you set infrequently, and
+  already has a well-defined starting point, so probably does not need
+  an application icon at Home.
+</p>
+
+<p>
+  <img src={@docRoot}images/activity_task_design/ActivityChooser.png>
+</p>
+
+      <li>
+          <b>Launch two or more main activities within a single
+          application from separate icon at Home</b> - As we have
+          defined it, all the code in a single .apk file is considered
+          to be one <em>application.</em> You can write an application
+          that contains two main activities launchable from Home.
+      </li>
+
+<p>
+  The Camera.apk application is a good example of an application that
+  contains two independent main activities &mdash; Camera and
+  Camcorder &mdash; that each have their own icons in application
+  launcher, that can be launched separately, and so appear to the user
+  as separate applications. They both share use of the same lens, and
+  both store their images (still and moving) in the Gallery.&nbsp;
+</p>
+
+<p>
+  In order for your application to contain two different, independent
+  activities launchable from Home, you must define them to be
+  associated with different tasks. (This means setting the main
+  activity for each task to a different <!--a href=#affinities
+  title=affinity-->task affinity<!--/a--> &mdash; in this case,
+  "com.android.camera" and "com.android.videocamera".)
+</p>
+
+<p>
+  Contacts and Dialer are another example of two main activities
+  launchable from Home that reside in the same application.
+</p>
+
+      <li>
+        <b>Making your application available as a widget</b> - An
+        application can also display a portion of itself as an <a
+        href={@docRoot}guide/topics/appwidgets/index.html title="app
+        widget">app widget</a>, embedded in Home or another
+        application, and receive periodic updates.
+      </li>
+
+    </ul>
+
+
+<h3 id=activities_added_to_task_tip>Allow your activities to be added to the current task</h3>
+
+<p>
+  If your activities can be started from another application, allow
+  them to be added to the current <a href=#tasks title=Tasks>task</a>
+  (or an existing task it has an affinity with). Having activities
+  added to a task enables the user to switch between a task that
+  contains your activities and other tasks. <!--See <a href=#tasks
+  title=Tasks>Tasks</a> for a fuller explanation.--> Exceptions are
+  your activities that have only one instance.&nbsp;
+</p>
+
+<p>
+  For this behavior, your activity should have a <!--a
+  href=launch_modes title="standard or singleTop"-->launch
+  mode<!--/a--> of standard or singleTop rather than singleTask or
+  singleInstance. These modes also enable multiple instances of your
+  activity to be run.
+</p>
+
+    
+<h3 id="notifications_return_tip">Notifications should be easy for the user to return from</h3>
+
+<p>
+  Applications that are in the background or haven't been run can
+  send out notifications to the user letting them know about events
+  of interest. For example, Calendar can send out notifications of
+  upcoming events, and Email can send out notifications when new
+  messages arrive. One of the user interface rules is that when the
+  user is in activity A and gets a notification for activity B and
+  picks that notification, when they press the BACK key, they should
+  go back to activity A.&nbsp;
+</p>
+
+<p>
+  The following scenario shows how the activity stack should work
+  when the user responds to a notification.
+</p>
+
+<ol>
+  <li>
+    User is creating a new event in Calendar. They realize they
+    need to copy part of an email message into this event
+  </li>
+  <li>
+    The user chooses Home &gt; Gmail
+  </li>
+  <li>
+    While in Gmail, they receive a notification from Calendar for an upcoming meeting
+  </li>
+  <li>
+    So they choose that notification, which takes them to a
+    dedicated Calendar activity that displays brief details of the
+    upcoming meeting
+  </li>
+  <li>
+    The user chooses this short notice to view further details
+  </li>
+  <li>
+    When done viewing the event, the user presses the BACK
+    key. They should be taken to Gmail, which is where they were
+    when they took the notification
+  </li>
+</ol>
+
+<p>
+This behavior doesn't necessarily happen by default.
+</p>
+
+<p>
+Notifications generally happen primarily in one of two ways:
+</p>
+
+  <ul>
+    <li>
+      <b>The application has a dedicated activity for
+      notification</b> - For example, when the user receives a
+      Calendar notification, the act of selecting that
+      notification starts a special activity that displays a list
+      of upcoming calendar events &mdash; a view available only
+      from the notification, not through the Calendar's own user
+      interface. After viewing this upcoming event, to ensure that
+      the user pressing the BACK key will return to the activity
+      the user was in when they picked the notification, you would
+      make sure this dedicated activity does not have the same
+      task affinity as the Calendar or any other activity. (You do
+      this by setting task affinity to the empty string, which
+      means it has no affinity to anything.) The explanation for
+      this follows.
+
+      <p>
+      Because of the way tasks work, if the taskAffinity of the
+      dedicated activity is kept as its default, then pressing the
+      BACK key (in step 6, above) would go to Calendar, rather
+      than Gmail. The reason is that, by default, all activities
+      in a given application have the same task
+      affinity. Therefore, the task affinity of the dedicated
+      activity matches the Calendar task, which is already running
+      in step 1. This means in step 4, choosing the notification
+      brings the existing Calendar event (in step 1) forward and
+      starts the dedicated activity on top of it.  This is not
+      what you want to have happen. Setting the dedicated
+      activity's taskAffinity to empty string fixes this.
+      </p>
+    </li>
+
+    <li>
+      <b>The user choosing the notification brings the activity to
+      the foreground in its initial state</b> - For example, in
+      response to a notification, the Gmail application is brought
+      to the foreground presenting the list of conversations. You
+      do this by having the user's response to the notification
+      trigger an intent to launch the activity with the clear top
+      flag set. (That is, you put {@link
+      android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP
+      FLAG_ACTIVITY_CLEAR_TOP} in the intent you pass to
+      startActivity()). This prevents Gmail from coming to the
+      foreground in whatever state the user last happened to be
+      viewing it.
+    </li>
+  </ul>
+
+<p>
+  There are other ways to handle notifications, such as bringing the
+  activity to the foreground set to display specific data, such as the
+  ongoing text message thread of a particular person.
+</p>
+
+<p>
+  A notification always starts an activity as a new task (that is, it
+  puts <font size=1>FLAG_ACTIVITY_NEW_TASK</font> in the intent it
+  passes to startActivity()). This is done because interruptions to a
+  task should not become part of that task.
+</p>
+
+<h3 id=use_notification_tip>Use the notification system &mdash; don't use dialog boxes in place of notifications</h3>
+
+<p>
+  If your background service needs to notify a user, use the standard
+  notification system &mdash; don't use a dialog or toast to notify
+  them. A dialog or toast would immediately take focus and interrupt
+  the user, taking focus away from what they were doing: the user
+  could be in the middle of typing text the moment the dialog appears
+  and could accidentally act on the dialog. Users are used to dealing
+  with notifications and can pull down the notification shade at their
+  convenience to respond to your message.
+</p>
+
+<h3 id=taking_over_back_key>Don't take over the BACK key unless you absolutely need to</h3>
+
+<p>
+  As a user navigates from one activity to the next, the system adds
+  them to the activity stack. This forms a navigation history that is
+  accessible with the BACK key. Most activities are relatively limited
+  in scope, with just one set of data, such as viewing a list of
+  contacts, composing an email, or taking a photo. But what if your
+  application is one big activity with several pages of content and
+  needs finer-grained control of the BACK key? Examples of such Google
+  applications are the Browser, which can have several web pages open
+  at once, and Maps, which can have several layers of geographic data
+  to switch between. Both of these applications take control of the
+  BACK key and maintain their own internal back stacks that operate
+  only when these applications have focus.
+</p>
+
+<p>
+  For example, Maps uses <em>layers</em> to present different
+  information on a map to the user: displaying the location of a
+  search result, displaying locations of friends, and displaying a
+  line for a street path providing direction between points. Maps
+  stores these layers in its own history so the BACK key can return to
+  a previous layer.
+</p>
+
+<p>
+  Similarly, Browser uses <em>browser windows</em> to present different
+  web pages to the user. Each window has its own navigation history,
+  equivalent to tabs in a browser in a desktop operating system (such
+  as Windows, Macintosh or Linux). For example, if you did a Google
+  web search in one window of the Android Browser, clicking on a link
+  in the search results displays a web page in that same window, and
+  then pressing BACK would to the search results page. Pressing
+  BACK goes to a previous window only if the current window was
+  launched from that previous window.  If the user keeps pressing
+  back, they will eventually leave the browser activity and return
+  Home.
+</p>
+
diff --git a/docs/html/guide/practices/ui_guidelines/index.jd b/docs/html/guide/practices/ui_guidelines/index.jd
index 61e310a..0b9d275 100644
--- a/docs/html/guide/practices/ui_guidelines/index.jd
+++ b/docs/html/guide/practices/ui_guidelines/index.jd
@@ -22,12 +22,24 @@
 filters that make it much simpler to create conforming icons.</dd>
 </dl>
  <dl>
-  <dt><a href="widget_design.html">Widget Design Guidelines</a> </dt>
+  <dt><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">Widget Design Guidelines</a> </dt>
   <dd>A widget displays an application's most important or timely information
 at a glance, on a user's Home screen. These design guidelines describe how to
 design widgets that fit with others on the Home screen. They include links to
 graphics files and templates that will make your designer's life easier.</dd>
 </dl>
+ <dl>
+  <dt><a href="{@docRoot}guide/practices/ui_guidelines/activity_task_design.html">Activity and Task Design Guidelines</a> </dt>
+  <dd>Activities are the basic, independent building blocks of applications.
+      As you design your application's UI and feature set, you are free to
+      re-use activities from other applications as if they were yours,
+      to enrich and extend your application.   These guidelines
+      describe how activities work, illustrates them with examples, and
+      describes important underlying principles and mechanisms, such as
+      multitasking, activity reuse, intents, the activity stack, and 
+      tasks. It covers this all from a high-level design perspective.
+</dd>
+</dl>
 
 
 
diff --git a/docs/html/images/activity_task_design/ActivityChooser.png b/docs/html/images/activity_task_design/ActivityChooser.png
new file mode 100644
index 0000000..6c20afb
--- /dev/null
+++ b/docs/html/images/activity_task_design/ActivityChooser.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ContactNew.png b/docs/html/images/activity_task_design/ContactNew.png
new file mode 100644
index 0000000..decaaeb
--- /dev/null
+++ b/docs/html/images/activity_task_design/ContactNew.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ContactView.png b/docs/html/images/activity_task_design/ContactView.png
new file mode 100644
index 0000000..5eff2ba
--- /dev/null
+++ b/docs/html/images/activity_task_design/ContactView.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ContactsDialer.png b/docs/html/images/activity_task_design/ContactsDialer.png
new file mode 100644
index 0000000..28794b7
--- /dev/null
+++ b/docs/html/images/activity_task_design/ContactsDialer.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ContactsList.png b/docs/html/images/activity_task_design/ContactsList.png
new file mode 100644
index 0000000..ef1b83f
--- /dev/null
+++ b/docs/html/images/activity_task_design/ContactsList.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskBasics1a.png b/docs/html/images/activity_task_design/HomeTaskBasics1a.png
new file mode 100644
index 0000000..eca4807
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskBasics1a.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskBasics1b.png b/docs/html/images/activity_task_design/HomeTaskBasics1b.png
new file mode 100644
index 0000000..ce76d63
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskBasics1b.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskBasics1c.png b/docs/html/images/activity_task_design/HomeTaskBasics1c.png
new file mode 100644
index 0000000..95f48c1
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskBasics1c.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskBasics1d.png b/docs/html/images/activity_task_design/HomeTaskBasics1d.png
new file mode 100644
index 0000000..bbb96d9
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskBasics1d.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskBasics1e.png b/docs/html/images/activity_task_design/HomeTaskBasics1e.png
new file mode 100644
index 0000000..09dd491
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskBasics1e.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching1a.png b/docs/html/images/activity_task_design/HomeTaskSwitching1a.png
new file mode 100644
index 0000000..de79aaf
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching1a.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching1b.png b/docs/html/images/activity_task_design/HomeTaskSwitching1b.png
new file mode 100644
index 0000000..bce7772
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching1b.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching1c.png b/docs/html/images/activity_task_design/HomeTaskSwitching1c.png
new file mode 100644
index 0000000..8209f2f
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching1c.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching2.png b/docs/html/images/activity_task_design/HomeTaskSwitching2.png
new file mode 100644
index 0000000..dee58a3
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching2.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching3a.png b/docs/html/images/activity_task_design/HomeTaskSwitching3a.png
new file mode 100644
index 0000000..0c90a86
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching3a.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching3b.png b/docs/html/images/activity_task_design/HomeTaskSwitching3b.png
new file mode 100644
index 0000000..4a16e69
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching3b.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/HomeTaskSwitching3c.png b/docs/html/images/activity_task_design/HomeTaskSwitching3c.png
new file mode 100644
index 0000000..d7789aa
--- /dev/null
+++ b/docs/html/images/activity_task_design/HomeTaskSwitching3c.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/IntentsDiagram.png b/docs/html/images/activity_task_design/IntentsDiagram.png
new file mode 100644
index 0000000..0ed366f
--- /dev/null
+++ b/docs/html/images/activity_task_design/IntentsDiagram.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/PhoneActivitiesDiagram.png b/docs/html/images/activity_task_design/PhoneActivitiesDiagram.png
new file mode 100644
index 0000000..8d346c1
--- /dev/null
+++ b/docs/html/images/activity_task_design/PhoneActivitiesDiagram.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ReplacingAnActivity.png b/docs/html/images/activity_task_design/ReplacingAnActivity.png
new file mode 100644
index 0000000..03b4d92
--- /dev/null
+++ b/docs/html/images/activity_task_design/ReplacingAnActivity.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ReusingAnActivity1.png b/docs/html/images/activity_task_design/ReusingAnActivity1.png
new file mode 100644
index 0000000..01c1729
--- /dev/null
+++ b/docs/html/images/activity_task_design/ReusingAnActivity1.png
Binary files differ
diff --git a/docs/html/images/activity_task_design/ReusingAnActivity2.png b/docs/html/images/activity_task_design/ReusingAnActivity2.png
new file mode 100644
index 0000000..288d2da
--- /dev/null
+++ b/docs/html/images/activity_task_design/ReusingAnActivity2.png
Binary files differ
diff --git a/docs/html/shareables/icon_templates-v1.0.zip b/docs/html/shareables/icon_templates-v1.0.zip
index 3e64f9aa..94fbcdc 100644
--- a/docs/html/shareables/icon_templates-v1.0.zip
+++ b/docs/html/shareables/icon_templates-v1.0.zip
Binary files differ
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 06f3820..bf62995 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -53,7 +53,8 @@
     TTS_FEATURE_UNSUPPORTED     = -2,
     TTS_VALUE_INVALID           = -3,
     TTS_PROPERTY_UNSUPPORTED    = -4,
-    TTS_PROPERTY_SIZE_TOO_SMALL = -5
+    TTS_PROPERTY_SIZE_TOO_SMALL = -5,
+    TTS_MISSING_RESOURCES       = -6
 };
 
 class TtsEngine
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 13e457f..324111b 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -817,19 +817,22 @@
         {
             AutoMutex lock(mHardwareLock);
             if (mForcedSpeakerCount++ == 0) {
-                mRouteRestoreTime = 0;
-                mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
-                if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
-                    LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
-                    mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
-                    usleep(mHardwareMixerThread->latency()*1000);
-                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
-                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
-                    mHardwareStatus = AUDIO_HW_IDLE;
-                    // delay track start so that audio hardware has time to siwtch routes
-                    usleep(kStartSleepTime);
+                if (mForcedRoute == 0) {
+                    mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+                    LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime);
+                    if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                        LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                        mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+                        usleep(mHardwareMixerThread->latency()*1000);
+                        mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                        mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                        mHardwareStatus = AUDIO_HW_IDLE;
+                        // delay track start so that audio hardware has time to siwtch routes
+                        usleep(kStartSleepTime);
+                    }
                 }
                 mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+                mRouteRestoreTime = 0;
             }
             LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
         }
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index e844350..397ddc8 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -114,7 +114,9 @@
     }
 
     if (mBitsMemory==0 || mSurface.data==0) {
-        LOGE("not enough memory for layer bitmap size=%u", size);
+        LOGE("not enough memory for layer bitmap "
+             "size=%u (w=%d, h=%d, stride=%d, format=%d)",
+             size, int(w), int(h), int(stride), int(format));
         allocator->dump("LayerBitmap");
         mSurface.data = 0;
         mSize = -1U;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 19ab0ad..d3743e6 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -468,6 +468,11 @@
          */
         native_setup(new WeakReference<MediaPlayer>(this));
     }
+
+    /*
+     * Update the MediaPlayer ISurface. Call after updating mSurface.
+     */
+    private native void _setVideoSurface();
   
     /**
      * Sets the SurfaceHolder to use for displaying the video portion of the media.
@@ -478,7 +483,12 @@
      */
     public void setDisplay(SurfaceHolder sh) {
         mSurfaceHolder = sh;
-        mSurface = sh.getSurface();
+        if (sh != null) {
+            mSurface = sh.getSurface();
+        } else {
+            mSurface = null;
+        }
+        _setVideoSurface();
         updateSurfaceScreenOn();
     }
 
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index 4b53756..54ca6c4 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -19,11 +19,11 @@
 
 
 /**
- * This class provides methods to play DTMF tones (ITU-T Recommendation Q.23), 
- * call supervisory tones (3GPP TS 22.001, CEPT) and proprietary tones (3GPP TS 31.111). 
+ * This class provides methods to play DTMF tones (ITU-T Recommendation Q.23),
+ * call supervisory tones (3GPP TS 22.001, CEPT) and proprietary tones (3GPP TS 31.111).
  * Depending on call state and routing options, tones are mixed to the downlink audio
- * or output to the speaker phone or headset. 
- * This API is not for generating tones over the uplink audio path.   
+ * or output to the speaker phone or headset.
+ * This API is not for generating tones over the uplink audio path.
  */
 public class ToneGenerator
 {
@@ -33,99 +33,99 @@
      * List of all available tones: These constants must be kept consistant with
      * the enum in ToneGenerator C++ class.     */
 
-	/**
+    /**
      * DTMF tone for key 0: 1336Hz, 941Hz, continuous</p>
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_0 = 0;
     /**
      * DTMF tone for key 1: 1209Hz, 697Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_1 = 1;
     /**
      * DTMF tone for key 2: 1336Hz, 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
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_4 = 4;
     /**
      * DTMF tone for key 5: 1336Hz, 770Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_5 = 5;
     /**
      * DTMF tone for key 6: 1477Hz, 770Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_6 = 6;
     /**
      * DTMF tone for key 7: 1209Hz, 852Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_7 = 7;
     /**
      * DTMF tone for key 8: 1336Hz, 852Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_8 = 8;
     /**
      * DTMF tone for key 9: 1477Hz, 852Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_9 = 9;
     /**
      * DTMF tone for key *: 1209Hz, 941Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_S = 10;
     /**
      * DTMF tone for key #: 1477Hz, 941Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_P = 11;
     /**
      * DTMF tone for key A: 1633Hz, 697Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_A = 12;
     /**
      * DTMF tone for key B: 1633Hz, 770Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_B = 13;
     /**
      * DTMF tone for key C: 1633Hz, 852Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_C = 14;
     /**
      * DTMF tone for key D: 1633Hz, 941Hz, continuous
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_DTMF_D = 15;
@@ -151,7 +151,7 @@
      * Call supervisory tone, Congestion:
      *      CEPT, JAPAN:    425Hz, 200ms ON, 200ms OFF...
      *      ANSI (IS-95):   480Hz+620Hz, 250ms ON, 250ms OFF...
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_CONGESTION = 18;
@@ -159,27 +159,28 @@
      * Call supervisory tone, Radio path acknowlegment :
      *      CEPT, ANSI:    425Hz, 200ms ON
      *      JAPAN:         400Hz, 1s ON, 2s OFF...
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_RADIO_ACK = 19;
     /**
      * Call supervisory tone, Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_RADIO_NOTAVAIL = 20;
     /**
      * Call supervisory tone, Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF...
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_ERROR = 21;
     /**
      * Call supervisory tone, Call Waiting:
      *      CEPT, JAPAN:    425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
-     *      ANSI (IS-95):   440 Hz, 300 ms ON, 9.7 s OFF, (100 ms ON, 100 ms OFF, 100 ms ON, 9.7s OFF ...)
-     * 
+     *      ANSI (IS-95):   440 Hz, 300 ms ON, 9.7 s OFF,
+     *                      (100 ms ON, 100 ms OFF, 100 ms ON, 9.7s OFF ...)
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_CALL_WAITING = 22;
@@ -187,42 +188,43 @@
      * Call supervisory tone, Ring Tone:
      *      CEPT, JAPAN:    425Hz, 1s ON, 4s OFF...
      *      ANSI (IS-95):   440Hz + 480Hz, 2s ON, 4s OFF...
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_RINGTONE = 23;
     /**
      * Proprietary tone, general beep: 400Hz+1200Hz, 35ms ON
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_PROP_BEEP = 24;
     /**
      * Proprietary tone, positive acknowlegement: 1200Hz, 100ms ON, 100ms OFF 2 bursts
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_PROP_ACK = 25;
     /**
      * Proprietary tone, negative acknowlegement: 300Hz+400Hz+500Hz, 400ms ON
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_PROP_NACK = 26;
     /**
      * Proprietary tone, prompt tone: 400Hz+1200Hz, 200ms ON
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int  TONE_PROP_PROMPT = 27;
     /**
      * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON
-     * 
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_PROP_BEEP2 = 28;
     /**
-     * Call supervisory tone (IS-95), intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms
+     * Call supervisory tone (IS-95), intercept tone: alternating 440 Hz and 620 Hz tones,
+     * each on for 250 ms
      *
      * @see #ToneGenerator(int, int)
      */
@@ -240,7 +242,8 @@
      */
     public static final int TONE_SUP_CONGESTION_ABBREV = 31;
     /**
-     * Call supervisory tone (IS-95), confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle
+     * Call supervisory tone (IS-95), confirm tone: a 350 Hz tone added to a 440 Hz tone
+     * repeated 3 times in a 100 ms on, 100 ms off cycle
      *
      * @see #ToneGenerator(int, int)
      */
@@ -253,6 +256,241 @@
     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
+     *
+     * @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
+     *
+     * @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
+     *
+     * @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;
+
+
+    /**
+     * 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_ISDN_NORMAL = 42;
+
+    /**
+     * 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_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;
+
+    /**
+     * 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_ISDN_PAT3 = 45;
+
+    /**
+     * 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_ISDN_RING_RING = 46;
+
+    /**
+     * 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_ISDN_PAT5 = 47;
+
+    /**
+     * 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_ISDN_PAT6 = 48;
+
+    /**
+     * 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_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;
+
     /** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
     public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
     /** Minimum volume setting, for use with {@link #ToneGenerator(int,int)} */
@@ -261,10 +499,10 @@
 
     /**
      * ToneGenerator class contructor specifying output stream type and volume.
-     * 
+     *
      * @param streamType The streame type used for tone playback (e.g. STREAM_MUSIC).
      * @param volume     The volume of the tone, given in percentage of maximum volume (from 0-100).
-     * 
+     *
      */
     public ToneGenerator(int streamType, int volume) {
         native_setup(streamType, volume);
@@ -272,7 +510,7 @@
 
     /**
      * This method starts the playback of a tone of the specified type.
-     * only one tone can play at a time: if a tone is playing while this method is called, 
+     * only one tone can play at a time: if a tone is playing while this method is called,
      * this tone is stopped and replaced by the one requested.
      * @param toneType   The type of tone generate chosen from the following list:
      * <ul>
@@ -328,9 +566,10 @@
     private native final void native_setup(int streamType, int volume);
 
     private native final void native_finalize();
+    
+    @Override
     protected void finalize() { native_finalize(); }
 
+    @SuppressWarnings("unused")
     private int mNativeContext; // accessed by native methods
-
-
 }
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 707db02..5abe451 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -198,6 +198,27 @@
     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
 }
 
+static void setVideoSurface(const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz)
+{
+    jobject surface = env->GetObjectField(thiz, fields.surface);
+    if (surface != NULL) {
+        const sp<Surface>& native_surface = get_surface(env, surface);
+        LOGV("prepare: surface=%p (id=%d)", 
+             native_surface.get(), native_surface->ID());
+        mp->setVideoSurface(native_surface);
+    }
+}
+
+static void
+android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz)
+{
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    setVideoSurface(mp, env, thiz);
+}
 
 static void
 android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
@@ -207,13 +228,7 @@
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    jobject surface = env->GetObjectField(thiz, fields.surface);
-    if (surface != NULL) {
-        const sp<Surface>& native_surface = get_surface(env, surface);
-        LOGV("prepare: surface=%p (id=%d)", 
-             native_surface.get(), native_surface->ID());
-        mp->setVideoSurface(native_surface);
-    }
+    setVideoSurface(mp, env, thiz);
     process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
 }
 
@@ -469,6 +484,7 @@
 static JNINativeMethod gMethods[] = {
     {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},
     {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
+    {"_setVideoSurface",    "()V",                              (void *)android_media_MediaPlayer_setVideoSurface},
     {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},
     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 0812650..ce80f92 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -44,23 +44,27 @@
     LOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d",
             maxChannels, streamType, srcQuality);
 
-    if (maxChannels > 32) {
-        LOGW("App requested %d channels, capped at 32", maxChannels);
-        maxChannels = 32;
+    // check limits
+    mMaxChannels = maxChannels;
+    if (mMaxChannels < 1) {
+        mMaxChannels = 1;
     }
+    else if (mMaxChannels > 32) {
+        mMaxChannels = 32;
+    }
+    LOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
 
     mQuit = false;
     mSoundPoolRef = soundPoolRef;
     mDecodeThread = 0;
-    mMaxChannels = maxChannels;
     mStreamType = streamType;
     mSrcQuality = srcQuality;
     mAllocated = 0;
     mNextSampleID = 0;
     mNextChannelID = 0;
 
-    mChannelPool = new SoundChannel[maxChannels];
-    for (int i = 0; i < maxChannels; ++i) {
+    mChannelPool = new SoundChannel[mMaxChannels];
+    for (int i = 0; i < mMaxChannels; ++i) {
         mChannelPool[i].init(this);
         mChannels.push_back(&mChannelPool[i]);
     }
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index ac59799..6908220 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -19,7 +19,7 @@
     
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.CAMERA" />
-    <uses-permission android:name="android.permission.WRITE_SDCARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <application>    
         <uses-library android:name="android.test.runner" />
         <activity android:label="@string/app_name"
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 2f0173d..4a2f823 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -68,6 +68,13 @@
         "/sdcard/recordVideoH263AudioMemOut.txt";
     private static final String AUDIO_ONLY_RECORD_MEMOUT =
         "/sdcard/recordAudioOnlyMemOut.txt";
+    //the tolerant memory leak
+    private static final int MAX_ACCEPTED_MEMORY_LEAK_KB = 150;
+
+    private static int mStartMemory = 0;
+    private static int mEndMemory = 0;
+    private static int mStartPid = 0;
+    private static int mEndPid = 0;
 
 
     public MediaPlayerPerformance() {
@@ -253,8 +260,21 @@
 
     //Write the ps output to the file
     public void getMemoryWriteToLog(Writer output) {
+        String memusage = null;
+        memusage = captureMediaserverInfo();
+        Log.v(TAG, memusage);
+        try {
+            //Write to file output
+            output.write(memusage);
+        } catch (Exception e) {
+            e.toString();
+        }
+    }
+
+    public String captureMediaserverInfo() {
         String cm = "ps mediaserver";
         String memoryUsage = null;
+
         int ch;
         try {
             Process p = Runtime.getRuntime().exec(cm);
@@ -267,18 +287,43 @@
         } catch (IOException e) {
             Log.v(TAG, e.toString());
         }
-
         String[] poList = memoryUsage.split("\r|\n|\r\n");
         String memusage = poList[1].concat("\n");
-        Log.v(TAG, memusage);
-        try {
-            //Write to file output
-            output.write(memusage);
-        } catch (Exception e) {
-            e.toString();
-        }
+        return memusage;
     }
 
+    public int getMediaserverPid(){
+        String memoryUsage = null;
+        int pidvalue = 0;
+        memoryUsage = captureMediaserverInfo();
+        String[] poList2 = memoryUsage.split("\t|\\s+");
+        String pid = poList2[1];
+        pidvalue = Integer.parseInt(pid);
+        Log.v(TAG, "PID = " + pidvalue);
+        return pidvalue;
+    }
+
+    public int getMediaserverVsize(){
+        String memoryUsage = captureMediaserverInfo();
+        String[] poList2 = memoryUsage.split("\t|\\s+");
+        String vsize = poList2[3];
+        int vsizevalue = Integer.parseInt(vsize);
+        Log.v(TAG, "VSIZE = " + vsizevalue);
+        return vsizevalue;
+    }
+
+    public boolean validateMemoryResult(int startPid, int startMemory){
+        mEndPid = getMediaserverPid();
+        mEndMemory = getMediaserverVsize();
+
+        //mediaserver crash
+        if (startPid != mEndPid)
+            return false;
+        //memory leak greter than the tolerant
+        if ((mEndMemory - startMemory) > MAX_ACCEPTED_MEMORY_LEAK_KB )
+            return false;
+        return true;
+    }
 
     @Suppress
     public void testWmaParseTime() throws Exception {
@@ -290,6 +335,10 @@
     // Test case 1: Capture the memory usage after every 20 h263 playback
     @LargeTest
     public void testH263VideoPlaybackMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File h263MemoryOut = new File(H263_VIDEO_PLAYBACK_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(h263MemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -297,11 +346,17 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("H263 playback memory test", memoryResult);
     }
 
     // Test case 2: Capture the memory usage after every 20 h264 playback
     @LargeTest
     public void testH264VideoPlaybackMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File h264MemoryOut = new File(H264_VIDEO_PLAYBACK_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(h264MemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -309,11 +364,17 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("H264 playback memory test", memoryResult);
     }
 
     // Test case 3: Capture the memory usage after each 20 WMV playback
     @LargeTest
     public void testWMVVideoPlaybackMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File wmvMemoryOut = new File(WMV_VIDEO_PLAYBACK_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -321,11 +382,17 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("wmv playback memory test", memoryResult);
     }
 
     // Test case 4: Capture the memory usage after every 20 video only recorded
     @LargeTest
     public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File videoH263RecordOnlyMemoryOut = new File(H263_VIDEO_ONLY_RECORD_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -334,11 +401,17 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("H263 record only memory test", memoryResult);
     }
 
     // Test case 5: Capture the memory usage after every 20 video only recorded
     @LargeTest
     public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File videoMp4RecordOnlyMemoryOut = new File(MP4_VIDEO_ONLY_RECORD_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -347,11 +420,18 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("mpeg4 record only memory test", memoryResult);
     }
 
-    // Test case 6: Capture the memory usage after every 20 video and audio recorded
+    // Test case 6: Capture the memory usage after every 20 video and audio
+    // recorded
     @LargeTest
     public void testRecordVidedAudioMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File videoRecordAudioMemoryOut = new File(H263_VIDEO_AUDIO_RECORD_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -360,11 +440,17 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("H263 audio video record memory test", memoryResult);
     }
 
     // Test case 7: Capture the memory usage after every 20 audio only recorded
     @LargeTest
     public void testRecordAudioOnlyMemoryUsage() throws Exception {
+        boolean memoryResult = false;
+        mStartPid = getMediaserverPid();
+        mStartMemory = getMediaserverVsize();
+
         File audioOnlyMemoryOut = new File(AUDIO_ONLY_RECORD_MEMOUT);
         Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut));
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -372,5 +458,7 @@
             getMemoryWriteToLog(output);
         }
         output.close();
+        memoryResult = validateMemoryResult(mStartPid, mStartMemory);
+        assertTrue("audio record only memory test", memoryResult);
     }
 }
diff --git a/opengl/tests/lighting1709/Android.mk b/opengl/tests/lighting1709/Android.mk
new file mode 100644
index 0000000..9563e61
--- /dev/null
+++ b/opengl/tests/lighting1709/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := LightingTest
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/lighting1709/AndroidManifest.xml b/opengl/tests/lighting1709/AndroidManifest.xml
new file mode 100644
index 0000000..6c23d42
--- /dev/null
+++ b/opengl/tests/lighting1709/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.lightingtest">
+
+    <application>
+        <activity android:name="ClearActivity" android:label="LightingTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java b/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java
new file mode 100644
index 0000000..3dc31cc
--- /dev/null
+++ b/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.lightingtest;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.app.Activity;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.MotionEvent;
+
+public class ClearActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        instance = counter++;
+        Log.e("ClearActivity", ":::::: onCreate: instance" + instance + " is created");
+        super.onCreate(savedInstanceState);
+        mGLView = new ClearGLSurfaceView(this);
+        setContentView(mGLView);
+    }
+
+    @Override
+    protected void onPause() {
+        Log.e("ClearActivity", ":::::: instance" + instance + " onPause: is called");
+        super.onPause();
+        mGLView.onPause();
+    }
+
+    @Override
+    protected void onResume() {
+        Log.e("ClearActivity", ":::::: instance" + instance + " onResume: is called");
+        super.onResume();
+        mGLView.onResume();
+    }
+
+    @Override
+    protected void onStop() {
+        Log.e("ClearActivity", ":::::: instance" + instance + " onStop: is called");
+        super.onStop();        
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.e("ClearActivity", ":::::: instance" + instance + " onDestroy: is called");
+        super.onDestroy();      
+    }
+
+    private GLSurfaceView mGLView;
+
+    private static int counter = 0;
+    private int        instance;
+}
+
+class ClearGLSurfaceView extends GLSurfaceView {
+    public ClearGLSurfaceView(Context context) {
+        super(context);
+        instance = counter++;
+        Log.e("ClearGLSurfaceView", ":::::: instance" + instance + " is created");
+        mRenderer = new ClearRenderer();
+        setRenderer(mRenderer);
+    }
+
+    public boolean onTouchEvent(final MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_MOVE: {// falling through on purpose here
+                Log.e("ClearGLSurfaceView", ":::::: instance" + instance + " onTouchEvent: handling down or move action");
+                queueEvent(new Runnable(){
+                    public void run() {
+                        mRenderer.setColor(event.getX() / getWidth(),
+                                event.getY() / getHeight(), 1.0f);
+                    }}
+                );
+                return true;
+            }
+            case MotionEvent.ACTION_UP: {
+                // launch a second instance of the same activity
+                Log.e("ClearGLSurfaceView", ":::::: instance" + instance + " onTouchEvent: handling up action");
+                //                      Intent intent = new Intent();
+                //                      intent.setClass(getContext(), ClearActivity.class);
+                //                      getContext().startActivity(intent);
+            }
+
+        }
+        return true;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        Log.e("ClearGLSurfaceView", ":::::: instance" + instance + " onDetachedFromWindow: is called");
+        super.onDetachedFromWindow();                  
+    }
+
+    ClearRenderer mRenderer;
+
+    private static int counter = 0;
+    private int instance;
+}
+
+class ClearRenderer implements GLSurfaceView.Renderer {
+    public ClearRenderer() {
+        instance = counter++;
+        Log.e("ClearRenderer", ":::::: instance" + instance + " is created");          
+    }
+
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        // Do nothing special.
+        Log.e("ClearRenderer", ":::::: instance" + instance + " onSurfaceCreated: is called");            
+    }
+
+    public void onSurfaceChanged(GL10 gl, int w, int h) {
+        Log.e("ClearRenderer", ":::::: instance" + instance + " onSurfaceChanged: is called");            
+
+        // Compute the projection matrix
+        gl.glMatrixMode(GL10.GL_PROJECTION);
+        gl.glLoadIdentity();
+
+        // Compute the boundaries of the frustum
+        float fl = (float) (-(w / 2)) / 288;
+        float fr = (float) (w / 2) / 288;
+        float ft = (float) (h / 2) / 288;
+        float fb = (float) (-(h / 2)) / 288;
+
+        // Set the view frustum
+        gl.glFrustumf(fl, fr, fb, ft, 1.0f, 2000.0f);
+
+        // Set the viewport dimensions
+        gl.glMatrixMode(GL10.GL_MODELVIEW);
+        gl.glLoadIdentity();
+        gl.glViewport(0, 0, w, h);
+    }
+
+    public void onDrawFrame(GL10 gl) {
+        //        gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
+        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+
+        float lightOff[]        = {0.0f, 0.0f, 0.0f, 1.0f};
+        float lightAmbient[]    = {5.0f, 0.0f, 0.0f, 1.0f};
+        float lightDiffuse[]    = {0.0f, 2.0f, 0.0f, 0.0f};
+        float lightPosAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
+        float lightPosSpot[]    = {0.0f, 0.0f, -8.0f, 1.0f};
+
+        
+        float v[] = new float[9];
+        ByteBuffer vbb = ByteBuffer.allocateDirect(v.length*4);
+        vbb.order(ByteOrder.nativeOrder());
+        FloatBuffer vb = vbb.asFloatBuffer();
+
+        gl.glDisable(GL10.GL_DITHER);
+
+        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, lightOff, 0);
+        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightOff, 0);
+        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0);
+        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPosAmbient, 0);
+        gl.glEnable(GL10.GL_LIGHT0);
+
+        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_SPECULAR, lightOff, 0);
+        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse, 0);
+        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightOff, 0);
+        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosSpot, 0);
+        gl.glLightf(GL10.GL_LIGHT1, GL10.GL_CONSTANT_ATTENUATION, 1.0f);
+        gl.glLightf(GL10.GL_LIGHT1, GL10.GL_LINEAR_ATTENUATION, 0.0f);
+        gl.glLightf(GL10.GL_LIGHT1, GL10.GL_QUADRATIC_ATTENUATION, 0.022f);
+        gl.glEnable(GL10.GL_LIGHT1);
+
+        gl.glEnable(GL10.GL_LIGHTING);
+
+        // draw upper left triangle
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        v[0] = -6f; v[1] = 0.5f; v[2] = -10f;
+        v[3] = -5f; v[4] = 2.5f; v[5] = -10f;
+        v[6] = -4f; v[7] = 0.5f; v[8] = -10f;
+        vb.put(v).position(0);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+        gl.glNormal3f(0, 0, 1);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+
+        // draw upper middle triangle
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        v[0] = -1f; v[1] = 0.5f; v[2] = -10f;
+        v[3] = 0f; v[4] = 2.5f; v[5] = -10f;
+        v[6] = 1f; v[7] = 0.5f; v[8] = -10f;
+        vb.put(v).position(0);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+        gl.glNormal3f(0, 0, 1);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+
+        // draw upper right triangle
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        v[0] = 4f; v[1] = 0.5f; v[2] = -10f;
+        v[3] = 5f; v[4] = 2.5f; v[5] = -10f;
+        v[6] = 6f; v[7] = 0.5f; v[8] = -10f;
+        vb.put(v).position(0);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+        gl.glNormal3f(0, 0, 1);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+
+        // draw lower left triangle
+        gl.glPushMatrix();
+        gl.glTranslatef(-5.0f, -1.5f, 0.0f);
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        v[0] = -1; v[1] = -1; v[2] = -10;
+        v[3] = 0; v[4] = 1; v[5] = -10;
+        v[6] = 1; v[7] = -1; v[8] = -10;
+        vb.put(v).position(0);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+        gl.glNormal3f(0, 0, 1);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+        gl.glPopMatrix();
+
+        // draw lower middle triangle
+        gl.glPushMatrix();
+        gl.glTranslatef(0.0f, -1.5f, 0.0f);
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        v[0] = -1; v[1] = -1; v[2] = -10;
+        v[3] = 0; v[4] = 1; v[5] = -10;
+        v[6] = 1; v[7] = -1; v[8] = -10;
+        vb.put(v).position(0);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+        gl.glNormal3f(0, 0, 1);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+        gl.glPopMatrix();
+
+        // draw lower right triangle
+        gl.glPushMatrix();
+        gl.glTranslatef(5.0f, -1.5f, 0.0f);
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        v[0] = -1; v[1] = -1; v[2] = -10;
+        v[3] = 0; v[4] = 1; v[5] = -10;
+        v[6] = 1; v[7] = -1; v[8] = -10;
+        vb.put(v).position(0);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+        gl.glNormal3f(0, 0, 1);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+        gl.glPopMatrix();      
+
+    }
+
+    public int[] getConfigSpec() {
+        Log.e("ClearRenderer", ":::::: instance" + instance + " getConfigSpec: is called");              
+        int[] configSpec = { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
+        return configSpec;      
+    }
+
+    public void setColor(float r, float g, float b) {
+        Log.e("ClearRenderer", ":::::: instance" + instance + " setColor: is called");              
+        mRed = r;
+        mGreen = g;
+        mBlue = b;
+    }
+
+    private float mRed;
+    private float mGreen;
+    private float mBlue;
+
+    private static int counter = 0;
+    private int instance;
+}
+
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index e3fff81..82ed1e3 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -16,17 +16,16 @@
 
 package com.android.server;
 
-import android.backup.BackupService;
-import android.backup.IBackupService;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.IBackupAgent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -49,6 +48,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 
 class BackupManagerService extends IBackupManager.Stub {
@@ -62,22 +62,28 @@
     
     private Context mContext;
     private PackageManager mPackageManager;
+    private final IActivityManager mActivityManager;
     private final BackupHandler mBackupHandler = new BackupHandler();
     // map UIDs to the set of backup client services within that UID's app set
-    private SparseArray<HashSet<ServiceInfo>> mBackupParticipants
-        = new SparseArray<HashSet<ServiceInfo>>();
+    private SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
+        = new SparseArray<HashSet<ApplicationInfo>>();
     // set of backup services that have pending changes
     private class BackupRequest {
-        public ServiceInfo service;
+        public ApplicationInfo appInfo;
         public boolean fullBackup;
         
-        BackupRequest(ServiceInfo svc, boolean isFull) {
-            service = svc;
+        BackupRequest(ApplicationInfo app, boolean isFull) {
+            appInfo = app;
             fullBackup = isFull;
         }
+
+        public String toString() {
+            return "BackupRequest{app=" + appInfo + " full=" + fullBackup + "}";
+        }
     }
     // Backups that we haven't started yet.
-    private HashMap<ComponentName,BackupRequest> mPendingBackups = new HashMap();
+    private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
+            = new HashMap<ApplicationInfo,BackupRequest>();
     // Backups that we have started.  These are separate to prevent starvation
     // if an app keeps re-enqueuing itself.
     private ArrayList<BackupRequest> mBackupQueue;
@@ -89,6 +95,7 @@
     public BackupManagerService(Context context) {
         mContext = context;
         mPackageManager = context.getPackageManager();
+        mActivityManager = ActivityManagerNative.getDefault();
 
         // Set up our bookkeeping
         mStateDir = new File(Environment.getDataDirectory(), "backup");
@@ -151,7 +158,7 @@
 
     // ----- Run the actual backup process asynchronously -----
 
-    private class BackupHandler extends Handler implements ServiceConnection {
+    private class BackupHandler extends Handler {
         public void handleMessage(Message msg) {
 
             switch (msg.what) {
@@ -163,31 +170,20 @@
                         for (BackupRequest b: mPendingBackups.values()) {
                             mBackupQueue.add(b);
                         }
-                        mPendingBackups = new HashMap<ComponentName,BackupRequest>();
+                        mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>();
                     }
                     // !!! TODO: start a new backup-queue journal file too
                     // WARNING: If we crash after this line, anything in mPendingBackups will
                     // be lost.  FIX THIS.
                 }
-                startOneService();
+                startOneAgent();
                 break;
             }
         }
-        
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "onServiceConnected name=" + name + " service=" + service);
-            IBackupService bs = IBackupService.Stub.asInterface(service);
-            processOneBackup(name, bs);
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-            // TODO: handle backup being interrupted
-        }
     }
 
-    void startOneService() {
+    void startOneAgent() {
         // Loop until we find someone to start or the queue empties out.
-        Intent intent = new Intent(BackupService.SERVICE_ACTION);
         while (true) {
             BackupRequest request;
             synchronized (mQueueLock) {
@@ -205,14 +201,19 @@
                 // Take it off the queue when we're done.
             }
             
-            intent.setClassName(request.service.packageName, request.service.name);
-            Log.d(TAG, "binding to " + intent);
+            Log.d(TAG, "starting agent for " + request);
+            // !!! TODO: need to handle the restore case?
+            int mode = (request.fullBackup)
+                    ? IApplicationThread.BACKUP_MODE_FULL
+                    : IApplicationThread.BACKUP_MODE_INCREMENTAL;
             try {
-                if (mContext.bindService(intent, mBackupHandler, Context.BIND_AUTO_CREATE)) {
-                    Log.d(TAG, "awaiting service object for " + intent);
+                if (mActivityManager.bindBackupAgent(request.appInfo, mode)) {
+                    Log.d(TAG, "awaiting agent for " + request);
                     // success
                     return;
                 }
+            } catch (RemoteException e) {
+                // can't happen; activity manager is local
             } catch (SecurityException ex) {
                 // Try for the next one.
                 Log.d(TAG, "error in bind", ex);
@@ -220,23 +221,23 @@
         }
     }
 
-    void processOneBackup(ComponentName name, IBackupService bs) {
-        try {
-            Log.d(TAG, "processOneBackup doBackup() on " + name);
+    void processOneBackup(String packageName, IBackupAgent bs) {
+        Log.d(TAG, "processOneBackup doBackup() on " + packageName);
 
-            BackupRequest request;
-            synchronized (mQueueLock) {
-                if (mBackupQueue == null) {
-                    Log.d(TAG, "mBackupQueue is null.  WHY?");
-                }
-                request = mBackupQueue.get(0);
+        BackupRequest request;
+        synchronized (mQueueLock) {
+            if (mBackupQueue == null) {
+                Log.d(TAG, "mBackupQueue is null.  WHY?");
             }
+            request = mBackupQueue.get(0);
+        }
 
+        try {
             // !!! TODO right now these naming schemes limit applications to
             // one backup service per package
-            File savedStateName = new File(mStateDir, request.service.packageName);
-            File backupDataName = new File(mDataDir, request.service.packageName + ".data");
-            File newStateName = new File(mStateDir, request.service.packageName + ".new");
+            File savedStateName = new File(mStateDir, request.appInfo.packageName);
+            File backupDataName = new File(mDataDir, request.appInfo.packageName + ".data");
+            File newStateName = new File(mStateDir, request.appInfo.packageName + ".new");
             
             // In a full backup, we pass a null ParcelFileDescriptor as
             // the saved-state "file"
@@ -280,7 +281,7 @@
             Log.d(TAG, "File not found on backup: ");
             fnf.printStackTrace();
         } catch (RemoteException e) {
-            Log.d(TAG, "Remote target " + name + " threw during backup:");
+            Log.d(TAG, "Remote target " + packageName + " threw during backup:");
             e.printStackTrace();
         } catch (Exception e) {
             Log.w(TAG, "Final exception guard in backup: ");
@@ -289,37 +290,45 @@
         synchronized (mQueueLock) {
             mBackupQueue.remove(0);
         }
-        mContext.unbindService(mBackupHandler);
+
+        if (request != null) {
+            try {
+                mActivityManager.unbindBackupAgent(request.appInfo);
+            } catch (RemoteException e) {
+                // can't happen
+            }
+        }
 
         // start the next one
-        startOneService();
+        startOneAgent();
     }
 
-    // Add the backup services in the given package to our set of known backup participants.
-    // If 'packageName' is null, adds all backup services in the system.
+    // Add the backup agents in the given package to our set of known backup participants.
+    // If 'packageName' is null, adds all backup agents in the whole system.
     void addPackageParticipantsLocked(String packageName) {
-        List<ResolveInfo> services = mPackageManager.queryIntentServices(
-                new Intent(BackupService.SERVICE_ACTION), 0);
-        addPackageParticipantsLockedInner(packageName, services);
+        // Look for apps that define the android:backupAgent attribute
+        List<ApplicationInfo> targetApps = allAgentApps();
+        addPackageParticipantsLockedInner(packageName, targetApps);
     }
 
-    private void addPackageParticipantsLockedInner(String packageName, List<ResolveInfo> services) {
-        for (ResolveInfo ri : services) {
-            if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
-                int uid = ri.serviceInfo.applicationInfo.uid;
-                HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
+    private void addPackageParticipantsLockedInner(String packageName,
+            List<ApplicationInfo> targetApps) {
+        if (DEBUG) {
+            Log.v(TAG, "Adding " + targetApps.size() + " backup participants:");
+            for (ApplicationInfo a : targetApps) {
+                Log.v(TAG, "    " + a + " agent=" + a.backupAgentName);
+            }
+        }
+
+        for (ApplicationInfo app : targetApps) {
+            if (packageName == null || app.packageName.equals(packageName)) {
+                int uid = app.uid;
+                HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
                 if (set == null) {
-                    set = new HashSet<ServiceInfo>();
+                    set = new HashSet<ApplicationInfo>();
                     mBackupParticipants.put(uid, set);
                 }
-                if (DEBUG) {
-                    Log.v(TAG, "Adding " + services.size() + " backup participants:");
-                    for (ResolveInfo svc : services) {
-                        Log.v(TAG, "    " + svc + " : " + svc.filter);
-                    }
-                }
-
-                set.add(ri.serviceInfo);
+                set.add(app);
             }
         }
     }
@@ -327,19 +336,30 @@
     // Remove the given package's backup services from our known active set.  If
     // 'packageName' is null, *all* backup services will be removed.
     void removePackageParticipantsLocked(String packageName) {
-        List<ResolveInfo> services = mPackageManager.queryIntentServices(
-                new Intent(BackupService.SERVICE_ACTION), 0);
-        removePackageParticipantsLockedInner(packageName, services);
+        List<ApplicationInfo> allApps = null;
+        if (packageName != null) {
+            allApps = new ArrayList<ApplicationInfo>();
+            try {
+                ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, 0);
+                allApps.add(app);
+            } catch (Exception e) {
+                // just skip it
+            }
+        } else {
+            // all apps with agents
+            allApps = allAgentApps();
+        }
+        removePackageParticipantsLockedInner(packageName, allApps);
     }
 
     private void removePackageParticipantsLockedInner(String packageName,
-            List<ResolveInfo> services) {
-        for (ResolveInfo ri : services) {
-            if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
-                int uid = ri.serviceInfo.applicationInfo.uid;
-                HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
+            List<ApplicationInfo> agents) {
+        for (ApplicationInfo app : agents) {
+            if (packageName == null || app.packageName.equals(packageName)) {
+                int uid = app.uid;
+                HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
                 if (set != null) {
-                    set.remove(ri.serviceInfo);
+                    set.remove(app);
                     if (set.size() == 0) {
                         mBackupParticipants.put(uid, null);
                     }
@@ -348,6 +368,21 @@
         }
     }
 
+    // Returns the set of all applications that define an android:backupAgent attribute
+    private List<ApplicationInfo> allAgentApps() {
+        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.backupAgentName == null) {
+                    allApps.remove(a);
+                }
+            }
+        }
+        return allApps;
+    }
+    
     // Reset the given package's known backup participants.  Unlike add/remove, the update
     // action cannot be passed a null package name.
     void updatePackageParticipantsLocked(String packageName) {
@@ -357,10 +392,9 @@
         }
 
         // brute force but small code size
-        List<ResolveInfo> services = mPackageManager.queryIntentServices(
-                new Intent(BackupService.SERVICE_ACTION), 0);
-        removePackageParticipantsLockedInner(packageName, services);
-        addPackageParticipantsLockedInner(packageName, services);
+        List<ApplicationInfo> allApps = allAgentApps();
+        removePackageParticipantsLockedInner(packageName, allApps);
+        addPackageParticipantsLockedInner(packageName, allApps);
     }
 
     // ----- IBackupManager binder interface -----
@@ -372,24 +406,29 @@
 
         Log.d(TAG, "dataChanged packageName=" + packageName);
         
-        HashSet<ServiceInfo> targets = mBackupParticipants.get(Binder.getCallingUid());
-        Log.d(TAG, "targets=" + targets);
+        HashSet<ApplicationInfo> targets = mBackupParticipants.get(Binder.getCallingUid());
         if (targets != null) {
             synchronized (mQueueLock) {
                 // Note that this client has made data changes that need to be backed up
-                for (ServiceInfo service : targets) {
+                for (ApplicationInfo app : targets) {
                     // validate the caller-supplied package name against the known set of
                     // packages associated with this uid
-                    if (service.packageName.equals(packageName)) {
+                    if (app.packageName.equals(packageName)) {
                         // Add the caller to the set of pending backups.  If there is
                         // one already there, then overwrite it, but no harm done.
-                        mPendingBackups.put(new ComponentName(service.packageName, service.name),
-                                new BackupRequest(service, true));
+                        BackupRequest req = new BackupRequest(app, false);
+                        mPendingBackups.put(app, req);
                         // !!! TODO: write to the pending-backup journal file in case of crash
                     }
                 }
 
-                Log.d(TAG, "Scheduling backup for " + mPendingBackups.size() + " participants");
+                if (DEBUG) {
+                    int numKeys = mPendingBackups.size();
+                    Log.d(TAG, "Scheduling backup for " + numKeys + " participants:");
+                    for (BackupRequest b : mPendingBackups.values()) {
+                        Log.d(TAG, "    + " + b + " agent=" + b.appInfo.backupAgentName);
+                    }
+                }
                 // Schedule a backup pass in a few minutes.  As backup-eligible data
                 // keeps changing, continue to defer the backup pass until things
                 // settle down, to avoid extra overhead.
@@ -402,22 +441,35 @@
     // that uid or package itself.
     public void scheduleFullBackup(String packageName) throws RemoteException {
         // !!! TODO: protect with a signature-or-system permission?
-        HashSet<ServiceInfo> targets = new HashSet<ServiceInfo>();
         synchronized (mQueueLock) {
             int numKeys = mBackupParticipants.size();
             for (int index = 0; index < numKeys; index++) {
                 int uid = mBackupParticipants.keyAt(index);
-                HashSet<ServiceInfo> servicesAtUid = mBackupParticipants.get(uid);
-                for (ServiceInfo service: servicesAtUid) {
-                    if (service.packageName.equals(packageName)) {
-                        mPendingBackups.put(new ComponentName(service.packageName, service.name),
-                                new BackupRequest(service, true));
+                HashSet<ApplicationInfo> servicesAtUid = mBackupParticipants.get(uid);
+                for (ApplicationInfo app: servicesAtUid) {
+                    if (app.packageName.equals(packageName)) {
+                        mPendingBackups.put(app, new BackupRequest(app, true));
                     }
                 }
             }
         }
     }
 
+    // Callback: a requested backup agent has been instantiated
+    public void agentConnected(String packageName, IBinder agentBinder) {
+        Log.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
+        IBackupAgent bs = IBackupAgent.Stub.asInterface(agentBinder);
+        processOneBackup(packageName, bs);
+    }
+
+    // Callback: a backup agent has failed to come up, or has unexpectedly quit.
+    // If the agent failed to come up in the first place, the agentBinder argument
+    // will be null.
+    public void agentDisconnected(String packageName) {
+        // TODO: handle backup being interrupted
+    }
+    
+
     
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -428,12 +480,18 @@
                 int uid = mBackupParticipants.keyAt(i);
                 pw.print("  uid: ");
                 pw.println(uid);
-                HashSet<ServiceInfo> services = mBackupParticipants.valueAt(i);
-                for (ServiceInfo s: services) {
+                HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
+                for (ApplicationInfo app: participants) {
                     pw.print("    ");
-                    pw.println(s.toString());
+                    pw.println(app.toString());
                 }
             }
+            pw.println("Pending:");
+            Iterator<BackupRequest> br = mPendingBackups.values().iterator();
+            while (br.hasNext()) {
+                pw.print("    ");
+                pw.println(br);
+            }
         }
     }
 }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 04e0253..c9bdd3c 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2843,7 +2843,7 @@
                                 if (npi.name.equals(perm)
                                         && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
                                     allowed = true;
-                                    Log.i(TAG, "Auto-granting WRITE_SDCARD to old pkg "
+                                    Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
                                             + pkg.packageName);
                                     break;
                                 }
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 88f47fd..b601ece 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -92,6 +92,13 @@
 
     private Bundle mCellLocation = new Bundle();
 
+    static final int PHONE_STATE_PERMISSION_MASK =
+                PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
+                PhoneStateListener.LISTEN_CALL_STATE |
+                PhoneStateListener.LISTEN_DATA_ACTIVITY |
+                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
+                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+
     // we keep a copy of all of the state so we can send it out when folks
     // register for it
     //
@@ -110,16 +117,8 @@
         // Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
         // Integer.toHexString(events));
         if (events != 0) {
-            // check permissions
-            if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
-                // ACCESS_FINE_LOCATION implies ACCESS_COARSE_LOCATION
-                if (mContext.checkCallingPermission(
-                        android.Manifest.permission.ACCESS_FINE_LOCATION)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    mContext.enforceCallingOrSelfPermission(
-                            android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
-                }
-            }
+            /* Checks permission and throws Security exception */
+            checkListenerPermission(events);
 
             synchronized (mRecords) {
                 // register
@@ -219,7 +218,7 @@
     }
 
     public void notifyCallState(int state, String incomingNumber) {
-        if (!checkPhoneStatePermission("notifyCallState()")) {
+        if (!checkNotifyPermission("notifyCallState()")) {
             return;
         }
         synchronized (mRecords) {
@@ -240,7 +239,7 @@
     }
 
     public void notifyServiceState(ServiceState state) {
-        if (!checkPhoneStatePermission("notifyServiceState()")) {
+        if (!checkNotifyPermission("notifyServiceState()")){
             return;
         }
         synchronized (mRecords) {
@@ -256,7 +255,7 @@
     }
 
     public void notifySignalStrength(SignalStrength signalStrength) {
-        if (!checkPhoneStatePermission("notifySignalStrength()")) {
+        if (!checkNotifyPermission("notifySignalStrength()")) {
             return;
         }
         synchronized (mRecords) {
@@ -281,7 +280,7 @@
     }
 
     public void notifyMessageWaitingChanged(boolean mwi) {
-        if (!checkPhoneStatePermission("notifyMessageWaitingChanged()")) {
+        if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
             return;
         }
         synchronized (mRecords) {
@@ -300,7 +299,7 @@
     }
 
     public void notifyCallForwardingChanged(boolean cfi) {
-        if (!checkPhoneStatePermission("notifyCallForwardingChanged()")) {
+        if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
             return;
         }
         synchronized (mRecords) {
@@ -319,7 +318,7 @@
     }
 
     public void notifyDataActivity(int state) {
-        if (!checkPhoneStatePermission("notifyDataActivity()")) {
+        if (!checkNotifyPermission("notifyDataActivity()" )) {
             return;
         }
         synchronized (mRecords) {
@@ -337,9 +336,9 @@
         }
     }
 
-    public void notifyDataConnection(int state, boolean isDataConnectivityPossible, String reason,
-            String apn, String interfaceName) {
-        if (!checkPhoneStatePermission("notifyDataConnection()")) {
+    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
+            String reason, String apn, String interfaceName) {
+        if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
         synchronized (mRecords) {
@@ -364,7 +363,7 @@
     }
 
     public void notifyDataConnectionFailed(String reason) {
-        if (!checkPhoneStatePermission("notifyDataConnectionFailed()")) {
+        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
             return;
         }
         /*
@@ -385,7 +384,7 @@
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
-        if (!checkPhoneStatePermission("notifyCellLocation()")) {
+        if (!checkNotifyPermission("notifyCellLocation()")) {
             return;
         }
         synchronized (mRecords) {
@@ -402,7 +401,7 @@
     /**
      * Copy the service state object so they can't mess it up in the local calls
      */
-    private void sendServiceState(Record r, ServiceState state) {
+    public void sendServiceState(Record r, ServiceState state) {
         try {
             r.callback.onServiceStateChanged(new ServiceState(state));
         } catch (RemoteException ex) {
@@ -533,7 +532,7 @@
         mContext.sendStickyBroadcast(intent);
     }
 
-    private boolean checkPhoneStatePermission(String method) {
+    private boolean checkNotifyPermission(String method) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                 == PackageManager.PERMISSION_GRANTED) {
             return true;
@@ -543,4 +542,17 @@
         Log.w(TAG, msg);
         return false;
     }
+
+    private void checkListenerPermission(int events) {
+        if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
+
+        }
+
+        if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PHONE_STATE, null);
+        }
+    }
 }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5fa8701..1528ba3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -588,6 +588,12 @@
 
     }
 
+    private void enforceMulticastChangePermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
+                "WifiService");
+    }
+
     /**
      * see {@link WifiManager#getWifiState()}
      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
@@ -1930,8 +1936,8 @@
         }
     }
 
-    public void enableMulticast(IBinder binder, String tag) {
-        enforceChangePermission();
+    public void acquireMulticastLock(IBinder binder, String tag) {
+        enforceMulticastChangePermission();
 
         synchronized (mMulticasters) {
             mMulticastEnabled++;
@@ -1953,8 +1959,8 @@
         }
     }
 
-    public void disableMulticast() {
-        enforceChangePermission();
+    public void releaseMulticastLock() {
+        enforceMulticastChangePermission();
 
         int uid = Binder.getCallingUid();
         synchronized (mMulticasters) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d1c40b4..3b26cb7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -42,6 +42,7 @@
 import android.app.Instrumentation;
 import android.app.PendingIntent;
 import android.app.ResultInfo;
+import android.backup.IBackupManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -131,6 +132,7 @@
     static final boolean DEBUG_PROCESSES = localLOGV || false;
     static final boolean DEBUG_USER_LEAVING = localLOGV || false;
     static final boolean DEBUG_RESULTS = localLOGV || false;
+    static final boolean DEBUG_BACKUP = localLOGV || true;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
     
@@ -633,6 +635,12 @@
             = new ArrayList<ServiceRecord>();
 
     /**
+     * Backup/restore process management
+     */
+    String mBackupAppName = null;
+    BackupRecord mBackupTarget = null;
+
+    /**
      * List of PendingThumbnailsRecord objects of clients who are still
      * waiting to receive all of the thumbnails for a task.
      */
@@ -4669,6 +4677,16 @@
                 mPendingBroadcast = null;
                 scheduleBroadcastsLocked();
             }
+            if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
+                Log.w(TAG, "Unattached app died before backup, skipping");
+                try {
+                    IBackupManager bm = IBackupManager.Stub.asInterface(
+                            ServiceManager.getService(Context.BACKUP_SERVICE));
+                    bm.agentDisconnected(app.info.packageName);
+                } catch (RemoteException e) {
+                    // Can't happen; the backup manager is local
+                }
+            }
         } else {
             Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
         }
@@ -4757,11 +4775,17 @@
                     mWaitForDebugger = mOrigWaitForDebugger;
                 }
             }
+            // If the app is being launched for restore or full backup, set it up specially
+            boolean isRestrictedBackupMode = false;
+            if (mBackupTarget != null && mBackupAppName.equals(processName)) {
+                isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
+                        || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
+            }
             thread.bindApplication(processName, app.instrumentationInfo != null
                     ? app.instrumentationInfo : app.info, providers,
                     app.instrumentationClass, app.instrumentationProfileFile,
                     app.instrumentationArguments, app.instrumentationWatcher, testMode, 
-                    mConfiguration, getCommonServicesLocked());
+                    isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
             updateLRUListLocked(app, false);
             app.lastRequestedGc = SystemClock.uptimeMillis();
         } catch (Exception e) {
@@ -4842,6 +4866,17 @@
             }
         }
 
+        // Check whether the next backup agent is in this process...
+        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
+            if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
+            try {
+                thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
+            } catch (Exception e) {
+                Log.w(TAG, "Exception scheduling backup agent creation: ");
+                e.printStackTrace();
+            }
+        }
+
         if (badApp) {
             // todo: Also need to kill application to deal with all
             // kinds of exceptions.
@@ -9118,6 +9153,18 @@
             app.receivers.clear();
         }
         
+        // If the app is undergoing backup, tell the backup manager about it
+        if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
+            if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
+            try {
+                IBackupManager bm = IBackupManager.Stub.asInterface(
+                        ServiceManager.getService(Context.BACKUP_SERVICE));
+                bm.agentDisconnected(app.info.packageName);
+            } catch (RemoteException e) {
+                // can't happen; backup manager is local
+            }
+        }
+
         // If the caller is restarting this app, then leave it in its
         // current lists and let the caller take care of it.
         if (restarting) {
@@ -10234,6 +10281,105 @@
     }
     
     // =========================================================
+    // BACKUP AND RESTORE
+    // =========================================================
+    
+    // Cause the target app to be launched if necessary and its backup agent
+    // instantiated.  The backup agent will invoke backupAgentCreated() on the
+    // activity manager to announce its creation.
+    public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
+        if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
+        enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
+
+        synchronized(this) {
+            // !!! TODO: currently no check here that we're already bound
+            BatteryStatsImpl.Uid.Pkg.Serv ss = null;
+            BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+            synchronized (stats) {
+                ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
+            }
+
+            BackupRecord r = new BackupRecord(ss, app, backupMode);
+            ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
+            // startProcessLocked() returns existing proc's record if it's already running
+            ProcessRecord proc = startProcessLocked(app.processName, app,
+                    false, 0, "backup", hostingName);
+            if (proc == null) {
+                Log.e(TAG, "Unable to start backup agent process " + r);
+                return false;
+            }
+
+            r.app = proc;
+            mBackupTarget = r;
+            mBackupAppName = app.packageName;
+
+            // If the process is already attached, schedule the creation of the backup agent now.
+            // If it is not yet live, this will be done when it attaches to the framework.
+            if (proc.thread != null) {
+                if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
+                try {
+                    proc.thread.scheduleCreateBackupAgent(app, backupMode);
+                } catch (RemoteException e) {
+                    // !!! TODO: notify the backup manager that we crashed, or rely on
+                    // death notices, or...?
+                }
+            } else {
+                if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
+            }
+            // Invariants: at this point, the target app process exists and the application
+            // is either already running or in the process of coming up.  mBackupTarget and
+            // mBackupAppName describe the app, so that when it binds back to the AM we
+            // know that it's scheduled for a backup-agent operation.
+        }
+        
+        return true;
+    }
+
+    // A backup agent has just come up                    
+    public void backupAgentCreated(String agentPackageName, IBinder agent) {
+        if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
+                + " = " + agent);
+
+        synchronized(this) {
+            if (!agentPackageName.equals(mBackupAppName)) {
+                Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
+                return;
+            }
+
+            try {
+                IBackupManager bm = IBackupManager.Stub.asInterface(
+                        ServiceManager.getService(Context.BACKUP_SERVICE));
+                bm.agentConnected(agentPackageName, agent);
+            } catch (RemoteException e) {
+                // can't happen; the backup manager service is local
+            } catch (Exception e) {
+                Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // done with this agent
+    public void unbindBackupAgent(ApplicationInfo appInfo) {
+        if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
+
+        synchronized(this) {
+            if (!mBackupAppName.equals(appInfo.packageName)) {
+                Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
+                return;
+            }
+
+            try {
+                mBackupTarget.app.thread.scheduleDestroyBackupAgent(appInfo);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception when unbinding backup agent:");
+                e.printStackTrace();
+            }
+            mBackupTarget = null;
+            mBackupAppName = null;
+        }
+    }
+    // =========================================================
     // BROADCASTS
     // =========================================================
 
diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/java/com/android/server/am/BackupRecord.java
new file mode 100644
index 0000000..5ac8e0d
--- /dev/null
+++ b/services/java/com/android/server/am/BackupRecord.java
@@ -0,0 +1,57 @@
+/*
+ * 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.am;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import android.content.pm.ApplicationInfo;
+
+/** @hide */
+class BackupRecord {
+    // backup/restore modes
+    public static final int BACKUP_NORMAL = 0;
+    public static final int BACKUP_FULL = 1;
+    public static final int RESTORE = 2;
+    
+    final BatteryStatsImpl.Uid.Pkg.Serv stats;
+    String stringName;                     // cached toString() output
+    final ApplicationInfo appInfo;         // information about BackupAgent's app
+    final int backupMode;                  // full backup / incremental / restore
+    ProcessRecord app;                     // where this agent is running or null
+
+    // ----- Implementation -----
+
+    BackupRecord(BatteryStatsImpl.Uid.Pkg.Serv _agentStats, ApplicationInfo _appInfo,
+            int _backupMode) {
+        stats = _agentStats;
+        appInfo = _appInfo;
+        backupMode = _backupMode;
+    }
+
+    public String toString() {
+        if (stringName != null) {
+            return stringName;
+        }
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("BackupRecord{")
+            .append(Integer.toHexString(System.identityHashCode(this)))
+            .append(' ').append(appInfo.packageName)
+            .append(' ').append(appInfo.name)
+            .append(' ').append(appInfo.backupAgentName).append('}');
+        return stringName = sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index af94100..42c885d 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -840,30 +840,10 @@
         updateDataIcon();
     }
 
-    // TODO(Teleca): I've add isCdma() to reduce some code duplication and simplify.
-    //               Please validate the correctness of these changes
     private boolean isCdma() {
-        // Is this equivalent, if so it seems simpler?
-//        return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
-
-        if (mServiceState != null) {
-            switch(mServiceState.getRadioTechnology()) {
-                case ServiceState.RADIO_TECHNOLOGY_1xRTT:
-                case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
-                case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
-                case ServiceState.RADIO_TECHNOLOGY_IS95A:
-                case ServiceState.RADIO_TECHNOLOGY_IS95B:
-                  return true;
-                default:
-                  return false;
-            }
-        } else {
-            return false;
-        }
+        return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
     }
 
-    // TODO(Teleca): I've add hasService() to reduce some code duplication and simplify.
-    //               Please validate the correctness of these changes.
     private boolean hasService() {
         if (mServiceState != null) {
             switch (mServiceState.getState()) {
@@ -1223,10 +1203,12 @@
     private final void updateCdmaRoamingIcon() {
         if (!hasService()) {
             mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
+            return;
         }
 
         if (!isCdma()) {
             mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
+            return;
         }
 
         int[] iconList = sRoamingIndicatorImages_cdma;
@@ -1256,8 +1238,10 @@
                 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
                 break;
             case EriInfo.ROAMING_ICON_MODE_FLASH:
-                mCdmaRoamingIndicatorIconData.iconId = com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
+                mCdmaRoamingIndicatorIconData.iconId =
+                        com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
                 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
+                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
                 break;
 
         }
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 8abafae..e113680 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -42,6 +42,9 @@
 
     /**
      * Listen for changes to the network signal strength (cellular).
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+     * READ_PHONE_STATE}
      * <p>
      *
      * @see #onSignalStrengthChanged
@@ -52,6 +55,9 @@
 
     /**
      * Listen for changes to the message-waiting indicator.
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+     * READ_PHONE_STATE}
      * <p>
      * Example: The status bar uses this to determine when to display the
      * voicemail icon.
@@ -62,7 +68,9 @@
 
     /**
      * Listen for changes to the call-forwarding indicator.
-     *
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+     * READ_PHONE_STATE}
      * @see #onCallForwardingIndicatorChanged
      */
     public static final int LISTEN_CALL_FORWARDING_INDICATOR                = 0x00000008;
@@ -85,7 +93,9 @@
 
     /**
      * Listen for changes to the device call state.
-     *
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+     * READ_PHONE_STATE}
      * @see #onCallStateChanged
      */
     public static final int LISTEN_CALL_STATE                               = 0x00000020;
@@ -100,7 +110,9 @@
     /**
      * Listen for changes to the direction of data traffic on the data
      * connection (cellular).
-     *
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+     * READ_PHONE_STATE}
      * Example: The status bar uses this to display the appropriate
      * data-traffic icon.
      *
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index e73de3c..f9b95b2 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -517,9 +517,14 @@
         return mWrappedSmsMessage.getUserData();
     }
 
-    /* Not part of the SDK interface and only needed by specific classes:
-       protected SmsHeader getUserDataHeader()
-    */
+    /**
+     * Return the user data header (UDH).
+     *
+     * @hide
+     */
+    public SmsHeader getUserDataHeader() {
+        return mWrappedSmsMessage.getUserDataHeader();
+    }
 
     /**
      * Returns the raw PDU for the message.
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index e78422e..dba4972 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -54,10 +54,11 @@
     protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList();
     protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList();
     protected RegistrantList mVoicePrivacyOffRegistrants = new RegistrantList();
-    protected RegistrantList mOtaSessionRegistrants = new RegistrantList();
-    protected RegistrantList mCallWaitingRegistrants = new RegistrantList();
-    protected RegistrantList mInformationRecordsRegistrants = new RegistrantList();
     protected Registrant mUnsolOemHookRawRegistrant;
+    protected RegistrantList mOtaProvisionRegistrants = new RegistrantList();
+    protected RegistrantList mCallWaitingInfoRegistrants = new RegistrantList();
+    protected RegistrantList mDisplayInfoRegistrants = new RegistrantList();
+    protected RegistrantList mSignalInfoRegistrants = new RegistrantList();
     protected Registrant mSMSRegistrant;
     protected Registrant mNITZTimeRegistrant;
     protected Registrant mSignalStrengthRegistrant;
@@ -464,6 +465,29 @@
         mRestrictedStateRegistrant.clear();
     }
 
+    public void registerForDisplayInfo(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mDisplayInfoRegistrants.add(r);
+    }
+
+    public void unregisterForDisplayInfo(Handler h) {
+        mDisplayInfoRegistrants.remove(h);
+    }
+
+    public void registerForCallWaitingInfo(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mCallWaitingInfoRegistrants.add(r);
+    }
+
+    public void unregisterForCallWaitingInfo(Handler h) {
+        mCallWaitingInfoRegistrants.remove(h);
+    }
+
+    public void registerForSignalInfo(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mSignalInfoRegistrants.add(r);
+    }
+
     public void setOnUnsolOemHookRaw(Handler h, int what, Object obj) {
         mUnsolOemHookRawRegistrant = new Registrant (h, what, obj);
     }
@@ -472,32 +496,19 @@
         mUnsolOemHookRawRegistrant.clear();
     }
 
-    public void registerForOtaSessionStatus(Handler h, int what, Object obj){
+    public void unregisterForSignalInfo(Handler h) {
+        mSignalInfoRegistrants.remove(h);
+    }
+   
+    public void registerForCdmaOtaProvision(Handler h,int what, Object obj){
         Registrant r = new Registrant (h, what, obj);
-        mOtaSessionRegistrants.add(r);
+        mOtaProvisionRegistrants.add(r); 
     }
 
-    public void unregisterForOtaSessionStatus(Handler h){
-        mOtaSessionRegistrants.remove(h);
+    public void unregisterForCdmaOtaProvision(Handler h){
+        mOtaProvisionRegistrants.remove(h);
     }
 
-    public void registerForCdmaCallWaiting(Handler h, int what, Object obj){
-        Registrant r = new Registrant (h, what, obj);
-        mCallWaitingRegistrants.add(r);
-    }
-
-    public void unregisterForCdmaCallWaiting(Handler h){
-        mCallWaitingRegistrants.remove(h);
-    }
-
-    public void registerCdmaInformationRecord(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-        mInformationRecordsRegistrants.add(r);
-    }
-
-    public void unregisterCdmaInformationRecord(Handler h) {
-        mInformationRecordsRegistrants.remove(h);
-    }
 
     //***** Protected Methods
     /**
diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java
index eb339f8..8263ded 100644
--- a/telephony/java/com/android/internal/telephony/CallTracker.java
+++ b/telephony/java/com/android/internal/telephony/CallTracker.java
@@ -56,6 +56,7 @@
     protected static final int EVENT_CONFERENCE_RESULT    = 11;
     protected static final int EVENT_SEPARATE_RESULT      = 12;
     protected static final int EVENT_ECT_RESULT           = 13;
+    protected static final int EVENT_EXIT_ECM_RESPONSE_CDMA = 14;
 
 
     protected void pollCallsWhenSafe() {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index da53e15..32f31ef 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -70,6 +70,12 @@
      */
     public String name;
     public String phoneNumber;
+
+    public String cnapName;
+    public int numberPresentation;
+    public int namePresentation;
+    public boolean contactExists;
+
     public String phoneLabel;
     /* Split up the phoneLabel into number type and label name */
     public int    numberType;
@@ -118,6 +124,7 @@
         info.numberLabel = null;
         info.cachedPhoto = null;
         info.isCachedPhotoCurrent = false;
+        info.contactExists = false;
         
         if (Config.LOGV) Log.v(TAG, "construct callerInfo from cursor");
         
@@ -176,6 +183,7 @@
                 columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL);
                 info.shouldSendToVoicemail = (columnIndex != -1) && 
                         ((cursor.getInt(columnIndex)) == 1);
+                info.contactExists = true;
             }
             cursor.close();
         }
@@ -303,4 +311,3 @@
         }
     }
 }    
-
diff --git a/telephony/java/com/android/internal/telephony/CdmaInformationRecord.java b/telephony/java/com/android/internal/telephony/CdmaInformationRecord.java
deleted file mode 100644
index 690df05..0000000
--- a/telephony/java/com/android/internal/telephony/CdmaInformationRecord.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-/**
- * TODO(Teleca): This class was poorly implemented and didn't
- * follow the Android coding conventions. It is now more or less
- * follows the conventions but there is still some work, see the
- * TODO's.
- */
-
-
-public class CdmaInformationRecord {
-    public int messageName;
-
-    public CdmaDisplayInfoRec displayInfoRec;
-    public CdmaNumberInfoRec numberInfoRec;
-    public CdmaSignalInfoRec signalInfoRec;
-    public CdmaRedirectingNumberInfoRec redirectingNumberInfoRec;
-    public CdmaLineControlInfoRec lineControlInfoRec;
-    public CdmaT53ClirInfoRec cdmaT53ClirInfoRec;
-    public CdmaT53AudioControlInfoRec cdmaT53AudioControlInfoRec;
-
-    public static final int RIL_CDMA_DISPLAY_INFO_REC = 0;
-    public static final int RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC = 1;
-    public static final int RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC = 2;
-    public static final int RIL_CDMA_CONNECTED_NUMBER_INFO_REC = 3;
-    public static final int RIL_CDMA_SIGNAL_INFO_REC = 4;
-    public static final int RIL_CDMA_REDIRECTING_NUMBER_INFO_REC = 5;
-    public static final int RIL_CDMA_LINE_CONTROL_INFO_REC = 6;
-    public static final int RIL_CDMA_EXTENDED_DISPLAY_INFO_REC = 7;
-    public static final int RIL_CDMA_T53_CLIR_INFO_REC = 8;
-    public static final int RIL_CDMA_T53_RELEASE_INFO_REC = 9;
-    public static final int RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC = 10;
-
-    public CdmaInformationRecord(int messageName) {
-        this.messageName = messageName;
-    }
-
-    void createDisplayInfo(int length, char buffer[]) {
-        displayInfoRec = new CdmaDisplayInfoRec(length, buffer);
-    }
-
-    void createNumberInfo(int length, char buffer[]) {
-        numberInfoRec = new CdmaNumberInfoRec(length, buffer);
-    }
-
-    void createSignalInfo(char buffer[]) {
-        signalInfoRec = new CdmaSignalInfoRec(buffer);
-    }
-
-    void createRedirectingNumberInfo(int length, char buffer[], int reason) {
-        redirectingNumberInfoRec = new CdmaRedirectingNumberInfoRec(length, buffer, reason);
-    }
-
-    void createLineControlInfo(char buffer[]) {
-        lineControlInfoRec = new CdmaLineControlInfoRec(buffer);
-    }
-
-    void createT53ClirInfo(char buffer) {
-        cdmaT53ClirInfoRec = new CdmaT53ClirInfoRec(buffer);
-    }
-
-    void createT53AudioControlInfo(char ul, char dl) {
-        cdmaT53AudioControlInfoRec = new CdmaT53AudioControlInfoRec(ul, dl);
-    }
-
-    /**
-     * TODO(Teleca): Add comments for each class giving the
-     * document and section where the information is defined
-     * as shown CdmaSignalInfoRec. Also add a toString to
-     * each of these to ease debugging.
-     */
-
-    /**
-     * Signal Information record from 3GPP2 C.S005 3.7.5.5
-     */
-    public static class CdmaSignalInfoRec {
-        public boolean isPresent;   /* non-zero if signal information record is present */
-        public int signalType;
-        public int alertPitch;
-        public int signalCode;
-
-        public CdmaSignalInfoRec() {}
-
-        public CdmaSignalInfoRec(char buffer[]) {
-            isPresent = buffer[0] == 1;
-            signalType = buffer[1];
-            alertPitch = buffer[2];
-            signalCode = buffer[3];
-        }
-
-        @Override
-        public String toString() {
-            return "CdmaSignalInfo: {" +
-                    " isPresent: " + isPresent +
-                    ", signalType: " + signalType +
-                    ", alertPitch: " + alertPitch +
-                    ", signalCode: " + signalCode +
-                    " }";
-        }
-    }
-
-    public static class CdmaDisplayInfoRec {
-        public char alphaLen;
-        public char alphaBuf[];
-
-        public CdmaDisplayInfoRec(int length, char buffer[]) {
-            alphaLen = (char)length;
-            alphaBuf = new char[length];
-            for(int i = 0; i < length; i++)
-                alphaBuf[i] = buffer[i];
-        }
-    }
-
-    public static class CdmaNumberInfoRec {
-        public int len;
-        public char buf[];
-        public char numberType;
-        public char numberPlan;
-        public char pi; // TODO(Teleca): poor name, no meaning
-        public char si; // TODO(Teleca): poor name
-
-        public CdmaNumberInfoRec(int length, char buffer[]) {
-            int i;
-
-            len = length;
-            buf = new char[length];
-            for (i = 0; i < len; i++) {
-                buf[i] = buffer[i];
-            }
-
-            numberType = buffer[i++];
-            numberPlan = buffer[i++];
-            pi = buffer[i++];
-            si = buffer[i++];
-        }
-    }
-
-    public static class CdmaRedirectingNumberInfoRec {
-        public static final int REASON_UNKNOWN = 0;
-        public static final int REASON_CALL_FORWARDING_BUSY = 1;
-        public static final int REASON_CALL_FORWARDING_NO_REPLY = 2;
-        public static final int REASON_CALLED_DTE_OUT_OF_ORDER = 9;
-        public static final int REASON_CALL_FORWARDING_BY_THE_CALLED_DTE = 10;
-        public static final int REASON_CALL_FORWARDING_UNCONDITIONAL = 15;
-
-        public CdmaNumberInfoRec numberInfoRec;
-        public int redirectingReason;
-
-        public CdmaRedirectingNumberInfoRec(int length, char buffer[], int reason) {
-            numberInfoRec = new CdmaNumberInfoRec(length, buffer);
-            redirectingReason = reason;
-        }
-    }
-
-    public static class CdmaLineControlInfoRec {
-        public char lineCtrlPolarityIncluded;
-        public char lineCtrlToggle;
-        public char lineCtrlReverse;
-        public char lineCtrlPowerDenial;
-
-        CdmaLineControlInfoRec(char buffer[]) {
-            lineCtrlPolarityIncluded = buffer[0];
-            lineCtrlToggle = buffer[1];
-            lineCtrlReverse = buffer[2];
-            lineCtrlPowerDenial = buffer[3];
-        }
-    }
-
-    // TODO(Teleca): A class for a single character, is this needed?
-    public static class CdmaT53ClirInfoRec {
-        public char cause;
-
-        public CdmaT53ClirInfoRec(char buffer) {
-            cause = buffer;
-        }
-    }
-
-    public static class CdmaT53AudioControlInfoRec {
-        public char uplink;
-        public char downlink;
-
-        public CdmaT53AudioControlInfoRec(char ul, char dl) {
-            uplink = ul;
-            downlink = dl;
-        }
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index ddf6b50..c6d1a4b 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -147,6 +147,14 @@
     static final int SIM_REFRESH_INIT           = 1;  // SIM initialized; reload all
     static final int SIM_REFRESH_RESET          = 2;  // SIM reset; may be locked
 
+    // GSM SMS fail cause for acknowledgeLastIncomingSMS. From TS 23.040, 9.2.3.22.
+    static final int GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED    = 0xD3;
+    static final int GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR           = 0xFF;
+
+    // CDMA SMS fail cause for acknowledgeLastIncomingCdmaSms.  From TS N.S00005, 6.5.2.125.
+    static final int CDMA_SMS_FAIL_CAUSE_RESOURCE_SHORTAGE          = 35;
+    static final int CDMA_SMS_FAIL_CAUSE_OTHER_TERMINAL_PROBLEM     = 39;
+
     //***** Methods
 
     RadioState getRadioState();
@@ -241,24 +249,6 @@
     void unregisterForRUIMReady(Handler h);
 
     /**
-     * Registers for the status of an OTASP/OTAPA session
-     */
-    void registerForOtaSessionStatus(Handler h, int what, Object obj);
-    void unregisterForOtaSessionStatus(Handler h);
-
-    /**
-      * register for Call waiting for CDMA
-      */
-    void registerForCdmaCallWaiting(Handler h, int what, Object obj);
-    void unregisterForCdmaCallWaiting(Handler h);
-
-    /**
-     * Registers for CDMA information records
-     */
-    void registerCdmaInformationRecord(Handler h, int what, Object obj);
-    void unregisterCdmaInformationRecord(Handler h);
-
-    /**
      * unlike the register* methods, there's only one new SMS handler
      * if you need to unregister, you should also tell the radio to stop
      * sending SMS's to you (via AT+CNMI)
@@ -344,16 +334,6 @@
     void unSetOnIccSmsFull(Handler h);
 
     /**
-     * Sets the handler for Emergency call-back Mode enter mesage.
-     * Unlike the register* methods, there's only one notification handler
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    void setEmergencyCallbackMode(Handler h, int what, Object obj);
-
-    /**
      * Sets the handler for SIM Refresh notifications.
      * Unlike the register* methods, there's only one notification handler
      *
@@ -452,6 +432,49 @@
     void setSuppServiceNotifications(boolean enable, Message result);
     //void unSetSuppServiceNotifications(Handler h);
 
+    /**
+     * Sets the handler for Event Notifications for CDMA Display Info.
+     * Unlike the register* methods, there's only one notification handler
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForDisplayInfo(Handler h, int what, Object obj);
+    void unregisterForDisplayInfo(Handler h);
+
+    /**
+     * Sets the handler for Event Notifications for CallWaiting Info.
+     * Unlike the register* methods, there's only one notification handler
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForCallWaitingInfo(Handler h, int what, Object obj);
+    void unregisterForCallWaitingInfo(Handler h);
+
+    /**
+     * Sets the handler for Event Notifications for Signal Info.
+     * Unlike the register* methods, there's only one notification handler
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForSignalInfo(Handler h, int what, Object obj);
+    void unregisterForSignalInfo(Handler h);
+
+    /**
+     * Fires on if Modem enters Emergency Callback mode
+     */
+    void setEmergencyCallbackMode(Handler h, int what, Object obj);
+
+     /**
+      * Fires on any CDMA OTA provision status change
+      */
+     void registerForCdmaOtaProvision(Handler h,int what, Object obj);
+     void unregisterForCdmaOtaProvision(Handler h);
 
     /**
      * Returns current ICC status.
@@ -867,9 +890,9 @@
 
     void setRadioPower(boolean on, Message response);
 
-    void acknowledgeLastIncomingSMS(boolean success, Message response);
+    void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message response);
 
-    void acknowledgeLastIncomingCdmaSms(boolean success, Message response);
+    void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response);
 
     /**
      * parameters equivilient to 27.007 AT+CRSM command
@@ -1072,6 +1095,12 @@
      */
     void setSmscAddress(String address, Message result);
 
+    /**
+     * Indicates whether there is storage available for new SMS messages.
+     * @param available true if storage is available
+     * @param result callback message
+     */
+    void reportSmsMemoryStatus(boolean available, Message result);
 
     void invokeOemRilRequestRaw(byte[] data, Message response);
 
@@ -1229,10 +1258,7 @@
      * @param result
      *            Callback message is empty on completion
      */
-    /**
-     * TODO(Teleca): configValuesArray is represented as a RIL_BroadcastSMSConfig
-     * so we think this should be a class with the appropriate parameters not an array?
-     */
+    // TODO: Change the configValuesArray to a RIL_BroadcastSMSConfig
     public void setCdmaBroadcastConfig(int[] configValuesArray, Message result);
 
     /**
@@ -1244,7 +1270,9 @@
     public void getCdmaBroadcastConfig(Message result);
 
     /**
-     * Requests the radio's system selection module to exit emergency callback mode.
+     *  Requests the radio's system selection module to exit emergency callback mode.
+     *  This function should only be called from CDMAPHone.java.
+     *
      * @param response callback message
      */
     public void exitEmergencyCallbackMode(Message response);
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index c6bbf82..237974d 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -73,6 +73,31 @@
     public abstract String getAddress();
 
     /**
+     * Gets cdma CNAP name  associated with connection
+     * @return cnap name or null if unavailable
+     */
+    public String getCnapName() {
+        return null;
+    }
+
+    /**
+     * Get orignal dial string
+     * @return orignal dial string or null if unavailable
+     */
+    public String getOrigDialString(){
+        return null;
+    }
+
+    /**
+     * Gets cdma CNAP presentation associated with connection
+     * @return cnap name or null if unavailable
+     */
+
+    public int getCnapNamePresentation() {
+       return 0;
+    };
+
+    /**
      * @return Call that owns this Connection, or null if none
      */
     public abstract Call getCall();
@@ -204,8 +229,14 @@
         WILD,           /* The post dial string playback is waiting for a
                            call to proceedAfterWildChar() */
         COMPLETE,       /* The post dial string playback is complete */
-        CANCELLED       /* The post dial string playback was cancelled
+        CANCELLED,       /* The post dial string playback was cancelled
                            with cancelPostDial() */
+        PAUSE           /* The post dial string playback is pausing for a 
+                           call to processNextPostDialChar*/
+    }
+
+    public void clearUserData(){
+        userData = null;
     }
 
     public abstract PostDialState getPostDialState();
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index d23af1f..77755ce 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -103,9 +103,9 @@
     /** Slow poll when attempting connection recovery. */
     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
     /** Default ping deadline, in seconds. */
-    protected final int DEFAULT_PING_DEADLINE = 5;
+    protected static final int DEFAULT_PING_DEADLINE = 5;
     /** Default max failure count before attempting to network re-registration. */
-    protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
+    protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
 
     /**
      * After detecting a potential connection problem, this is the max number
@@ -217,7 +217,7 @@
     }
 
     // abstract handler methods
-    protected abstract void onTrySetupData();
+    protected abstract void onTrySetupData(String reason);
     protected abstract void onRoamingOff();
     protected abstract void onRoamingOn();
     protected abstract void onRadioAvailable();
@@ -232,7 +232,11 @@
         switch (msg.what) {
 
             case EVENT_TRY_SETUP_DATA:
-                onTrySetupData();
+                String reason = null;
+                if (msg.obj instanceof String) {
+                    reason = (String)msg.obj;
+                }
+                onTrySetupData(reason);
                 break;
 
             case EVENT_ROAMING_OFF:
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index cc6b452..6e6f64c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -238,5 +238,10 @@
      */
     String getCdmaEriText();
 
+    /**
+      * Returns the unread count of voicemails
+      */
+    int getCountVoiceMessages();
+
 }
 
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 4d0cf41..260f662 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -102,6 +102,7 @@
     static final String DATA_APN_KEY = "apn";
     static final String DATA_IFACE_NAME_KEY = "iface";
     static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
+    static final String PHONE_IN_ECM_STATE = "phoneinECMState";
 
     /**
      * APN types for data connections.  These are usage categories for an APN
@@ -195,6 +196,24 @@
     static final int TTY_MODE_HCO = 2;
     static final int TTY_MODE_VCO = 3;
 
+     /**
+     * CDMA OTA PROVISION STATUS, the same as RIL_CDMA_OTA_Status in ril.h
+     */
+
+    public static final int CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED = 0;
+    public static final int CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED = 1;
+    public static final int CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED = 2;
+    public static final int CDMA_OTA_PROVISION_STATUS_SSD_UPDATED = 3;
+    public static final int CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED = 4;
+    public static final int CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED = 5;
+    public static final int CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED = 6;
+    public static final int CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED = 7;
+    public static final int CDMA_OTA_PROVISION_STATUS_COMMITTED = 8;
+    public static final int CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED = 9;
+    public static final int CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED = 10;
+    public static final int CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED = 11;
+
+
     /**
      * Get the current ServiceState. Use
      * <code>registerForServiceStateChanged</code> to be informed of
@@ -273,7 +292,12 @@
     String getActiveApn();
 
     /**
-     * Get current signal strength.
+     * Get current signal strength. No change notification available on this
+     * interface. Use <code>PhoneStateNotifier</code> or an equivalent.
+     * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu).
+     * The following special values are defined:</p>
+     * <ul><li>0 means "-113 dBm or less".</li>
+     * <li>31 means "-51 dBm or greater".</li></ul>
      *
      * @return Current signal strength as SignalStrength
      */
@@ -499,53 +523,21 @@
     void unregisterForInCallVoicePrivacyOff(Handler h);
 
     /**
-     * Register for notifications about information record available
+     * Register for notifications when CDMA OTA Provision status change
      *
      * @param h Handler that receives the notification message.
      * @param what User-defined message code.
      * @param obj User object.
      */
-    void registerCdmaInformationRecord(Handler h, int what, Object obj);
+    void registerForCdmaOtaStatusChange(Handler h, int what, Object obj);
 
     /**
-     * Unregister for notifications about information record available
-     *
+     * Unegister for notifications when CDMA OTA Provision status change
      * @param h Handler to be removed from the registrant list.
      */
-    void unregisterCdmaInformationRecord(Handler h);
+    void unregisterForCdmaOtaStatusChange(Handler h);
 
     /**
-     * Register for the indication of OTA status change
-     *
-     * @param h Handler that receives the notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    void registerForOtaStatusChange(Handler h, int what, Object obj);
-
-    /**
-     * Unregister for the indication of OTA status change
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    void unregisterForOtaStatusChange(Handler h);
-
-    /**
-     * Register for the indication of Cdma Call Waiting
-     *
-     * @param h Handler that receives the notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    void registerForCdmaCallWaiting(Handler h, int what, Object obj);
-
-    /**
-     * Unregister for the indication of Cdma Call Waiting
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    void unregisterForCdmaCallWaiting(Handler h);
-    /**
      * Returns SIM record load state. Use
      * <code>getSimCard().registerForReady()</code> for change notification.
      *
@@ -760,9 +752,18 @@
     void stopDtmf();
 
     /**
-     * Play a Burst of DTMF tone on the active call. Ignored if there is no active call.
+     * send burst DTMF tone, it can send the string as single character or multiple character
+     * ignore if there is no active call or not valid digits string.
+     * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
+     * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
+     * this api can send single character and multiple character, also, this api has response
+     * back to caller.
+     *
+     * @param dtmfString is string representing the dialing digit(s) in the active call
+     * @param onCompelte is the callback message when the action is processed by BP
+     *
      */
-    void sendBurstDtmf(String dtmfString);
+    void sendBurstDtmf(String dtmfString, Message onComplete);
 
     /**
      * Sets the radio power on/off state (off is sometimes
@@ -827,6 +828,12 @@
     String getVoiceMailNumber();
 
     /**
+     * Returns unread voicemail count. This count is shown when the  voicemail
+     * notification is expanded.<p>
+     */
+    int getCountVoiceMessages();
+
+    /**
      * Returns the alpha tag associated with the voice mail number.
      * If there is no alpha tag associated or the record is not yet available,
      * returns a default localized string. <p>
@@ -859,7 +866,7 @@
      *
      * @param commandInterfaceCFReason is one of the valid call forwarding
      *        CF_REASONS, as defined in
-     *        <code>com.android.internal.telephony.CommandsInterface./code>
+     *        <code>com.android.internal.telephony.CommandsInterface.</code>
      * @param onComplete a callback message when the action is completed.
      *        @see com.android.internal.telephony.CallForwardInfo for details.
      */
@@ -872,10 +879,10 @@
      *
      * @param commandInterfaceCFReason is one of the valid call forwarding
      *        CF_REASONS, as defined in
-     *        <code>com.android.internal.telephony.CommandsInterface./code>
+     *        <code>com.android.internal.telephony.CommandsInterface.</code>
      * @param commandInterfaceCFAction is one of the valid call forwarding
      *        CF_ACTIONS, as defined in
-     *        <code>com.android.internal.telephony.CommandsInterface./code>
+     *        <code>com.android.internal.telephony.CommandsInterface.</code>
      * @param dialingNumber is the target phone number to forward calls to
      * @param timerSeconds is used by CFNRy to indicate the timeout before
      *        forwarding is attempted.
@@ -1335,10 +1342,16 @@
 
     //***** CDMA support methods
 
+    /*
+     * TODO(Moto) TODO(Teleca): can getCdmaMin, getEsn, getMeid use more generic calls
+     * already defined getXxxx above?
+     */
+
     /**
      * Retrieves the MIN for CDMA phones.
      */
-    String getMin();
+    
+    String getCdmaMin();
 
     /**
      * Retrieves the ESN for CDMA phones.
@@ -1384,14 +1397,6 @@
     void queryTTYMode(Message onComplete);
 
     /**
-     * exitEmergencyCallbackMode
-     * exits the emergency callback mode
-     *
-     * @param onComplete a callback message when the action is completed.
-     */
-    void exitEmergencyCallbackMode(Message onComplete);
-
-    /**
      * Activate or deactivate cell broadcast SMS.
      *
      * @param activate
@@ -1438,4 +1443,93 @@
      */
     public String getCdmaEriText();
 
+    /**
+     * request to exit emergency call back mode
+     * the caller should use setOnECMModeExitResponse
+     * to receive the emergency callback mode exit response
+     */
+    void exitEmergencyCallbackMode();
+
+    /**
+     * this decides if the dial number is OTA(Over the air provision) number or not
+     * @param dialStr is string representing the dialing digit(s)
+     * @return  true means the dialStr is OTA number, and false means the dialStr is not OTA number
+     */
+    boolean isOtaSpNumber(String dialStr);
+
+    /**
+     * Register for notifications when CDMA call waiting comes
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    // TODO(Moto) TODO: Remove when generic implemented
+    void registerForCallWaiting(Handler h, int what, Object obj);
+
+    /**
+     * Unegister for notifications when CDMA Call waiting comes
+     * @param h Handler to be removed from the registrant list.
+     */
+    // TODO(Moto): Remove when generic implemented
+    void unregisterForCallWaiting(Handler h);
+
+
+    /**
+     * Register for signal information notifications from the network.
+     * Message.obj will contain an AsyncResult.
+     * AsyncResult.result will be a SuppServiceNotification instance.
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+
+    void registerForSignalInfo(Handler h, int what, Object obj) ;
+    /**
+     * Unregisters for signal information notifications.
+     * Extraneous calls are tolerated silently
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    void unregisterForSignalInfo(Handler h);
+
+    /**
+     * Register for display information notifications from the network.
+     * Message.obj will contain an AsyncResult.
+     * AsyncResult.result will be a SuppServiceNotification instance.
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForDisplayInfo(Handler h, int what, Object obj);
+
+    /**
+     * Unregisters for display information notifications.
+     * Extraneous calls are tolerated silently
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    void unregisterForDisplayInfo(Handler h) ;
+
+
+    /**
+     * registers for exit emergency call back mode request response
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+
+    void setOnEcbModeExitResponse(Handler h, int what, Object obj);
+
+    /**
+     * Unregisters for exit emergency call back mode request response
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    void unsetOnEcbModeExitResponse(Handler h);
+
+
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 7234aa3..d6b2737 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -53,15 +53,6 @@
  *
  */
 
-/**
- * TODO(Teleca): This has a multitude of methods that are CDMA specific
- * , (registerForVoicePrivacy, registerCdmaInformationRecord, registerCdmaCallWaiting,
- * setCdmaRoamingPreference, setCdmaSubscription, getCdmaEriIcon, getCdmaEriText, ...) can
- * these type of calls be more abstract. For example CallWaiting is common between the GSM/CDMA
- * it would seem that doesn't need to be cdma specific. Also, should the application be directly
- * dealing with the CdmaInformationRecord's could they be abstracted to something more generic.
- */
-
 public abstract class PhoneBase implements Phone {
     private static final String LOG_TAG = "PHONE";
     private static final boolean LOCAL_DEBUG = true;
@@ -100,8 +91,8 @@
     protected static final int EVENT_RUIM_RECORDS_LOADED            = 21;
     protected static final int EVENT_NV_READY                       = 22;
     protected static final int EVENT_SET_ENHANCED_VP                = 23;
-    protected static final int EVENT_CDMA_CALL_WAITING              = 24;
-    protected static final int EVENT_EMERGENCY_CALLBACK_MODE        = 25;
+    protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER  = 24;
+    protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 25;
 
     // Key used to read/write current CLIR setting
     public static final String CLIR_KEY = "clir_key";
@@ -294,36 +285,6 @@
         mCM.unregisterForInCallVoicePrivacyOff(h);
     }
 
-    // Inherited documentation suffices.
-    public void registerForOtaStatusChange(Handler h, int what, Object obj){
-        mCM.registerForOtaSessionStatus(h,what,obj);
-    }
-
-    // Inherited documentation suffices.
-    public void unregisterForOtaStatusChange(Handler h){
-        mCM.unregisterForOtaSessionStatus(h);
-    }
-
-    // Inherited documentation suffices.
-    public void registerCdmaInformationRecord(Handler h, int what, Object obj){
-        mCM.registerCdmaInformationRecord(h,what,obj);
-    }
-
-    // Inherited documentation suffices.
-    public void unregisterCdmaInformationRecord(Handler h){
-        mCM.unregisterCdmaInformationRecord(h);
-    }
-
-    // Inherited documentation suffices.
-    public void registerForCdmaCallWaiting(Handler h, int what, Object obj){
-        mCM.registerForCdmaCallWaiting(h,what,obj);
-    }
-
-    // Inherited documentation suffices.
-    public void unregisterForCdmaCallWaiting(Handler h){
-        mCM.unregisterForCdmaCallWaiting(h);
-    }
-
     /**
      * Notifiy registrants of a new ringing Connection.
      * Subclasses of Phone probably want to replace this with a
@@ -631,14 +592,6 @@
     }
 
     /**
-     *  Send the exit emergency callback mode message
-     */
-    public void exitEmergencyCallbackMode(Message onComplete) {
-        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
-        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
-    }
-
-    /**
      * This should only be called in GSM mode.
      * Only here for some backward compatibility
      * issues concerning the GSMPhone class.
@@ -684,6 +637,11 @@
 
     public abstract String getPhoneName();
 
+    /** @hide */
+    public int getCountVoiceMessages(){
+        return 0;
+    }
+
     /**
      * Returns the CDMA ERI icon index to display
      */
@@ -710,4 +668,71 @@
         return "GSM nw, no ERI";
     }
 
+    public String getCdmaMin() {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        return null;
+    }
+
+    public void sendBurstDtmf(String dtmfString, Message onComplete) {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void exitEmergencyCallbackMode() {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void unregisterForCdmaOtaStatusChange(Handler h) {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public  boolean isOtaSpNumber(String dialStr) {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        return false;
+    }
+
+    public void registerForCallWaiting(Handler h, int what, Object obj){
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void unregisterForCallWaiting(Handler h){
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void registerForSignalInfo(Handler h, int what, Object obj) {
+        mCM.registerForSignalInfo(h, what, obj);
+    }
+
+    public void unregisterForSignalInfo(Handler h) {
+        mCM.unregisterForSignalInfo(h);
+    }
+
+    public void registerForDisplayInfo(Handler h, int what, Object obj) {
+        mCM.registerForDisplayInfo(h, what, obj);
+    }
+
+     public void unregisterForDisplayInfo(Handler h) {
+         mCM.unregisterForDisplayInfo(h);
+     }
+
+     public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
+         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+     }
+
+     public void unsetOnEcbModeExitResponse(Handler h){
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+     }
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index a329cbb..7d968f9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -306,28 +306,12 @@
         mActivePhone.unregisterForInCallVoicePrivacyOff(h);
     }
 
-    public void registerCdmaInformationRecord(Handler h, int what, Object obj) {
-        mActivePhone.registerCdmaInformationRecord(h,what,obj);
+    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
+        mActivePhone.registerForCdmaOtaStatusChange(h,what,obj);
     }
 
-    public void unregisterCdmaInformationRecord(Handler h) {
-        mActivePhone.unregisterCdmaInformationRecord(h);
-    }
-
-    public void registerForOtaStatusChange(Handler h, int what, Object obj){
-        mActivePhone.registerForOtaStatusChange(h,what,obj);
-    }
-
-    public void unregisterForOtaStatusChange(Handler h){
-        mActivePhone.unregisterForOtaStatusChange(h);
-    }
-
-    public void registerForCdmaCallWaiting(Handler h, int what, Object obj){
-        mActivePhone.registerForCdmaCallWaiting(h,what,obj);
-    }
-
-    public void unregisterForCdmaCallWaiting(Handler h){
-        mActivePhone.unregisterForCdmaCallWaiting(h);
+    public void unregisterForCdmaOtaStatusChange(Handler h) {
+         mActivePhone.unregisterForCdmaOtaStatusChange(h);
     }
 
     public boolean getIccRecordsLoaded() {
@@ -414,10 +398,6 @@
         mActivePhone.stopDtmf();
     }
 
-    public void sendBurstDtmf(String dtmfString) {
-        mActivePhone.sendBurstDtmf(dtmfString);
-    }
-
     public void setRadioPower(boolean power) {
         mActivePhone.setRadioPower(power);
     }
@@ -434,6 +414,10 @@
         return mActivePhone.getLine1Number();
     }
 
+    public String getCdmaMin() {
+        return mActivePhone.getCdmaMin();
+    }
+
     public String getLine1AlphaTag() {
         return mActivePhone.getLine1AlphaTag();
     }
@@ -446,6 +430,11 @@
         return mActivePhone.getVoiceMailNumber();
     }
 
+     /** @hide */
+    public int getCountVoiceMessages(){
+        return mActivePhone.getCountVoiceMessages();
+    }
+
     public String getVoiceMailAlphaTag() {
         return mActivePhone.getVoiceMailAlphaTag();
     }
@@ -656,10 +645,6 @@
         return mActivePhone.getIccSerialNumber();
     }
 
-    public String getMin() {
-        return mActivePhone.getMin();
-    }
-
     public String getEsn() {
         return mActivePhone.getEsn();
     }
@@ -688,10 +673,6 @@
         mActivePhone.queryTTYMode(onComplete);
     }
 
-    public void exitEmergencyCallbackMode(Message onComplete) {
-        mActivePhone.exitEmergencyCallbackMode(onComplete);
-    }
-
     public void activateCellBroadcastSms(int activate, Message response) {
         mActivePhone.activateCellBroadcastSms(activate, response);
     }
@@ -720,12 +701,55 @@
          return mActivePhone.getCdmaEriIconIndex();
     }
 
+     public String getCdmaEriText() {
+         return mActivePhone.getCdmaEriText();
+     }
+
     public int getCdmaEriIconMode() {
          return mActivePhone.getCdmaEriIconMode();
     }
 
-    public String getCdmaEriText() {
-         return mActivePhone.getCdmaEriText();
+    public void sendBurstDtmf(String dtmfString, Message onComplete){
+        mActivePhone.sendBurstDtmf(dtmfString,onComplete);
+    }
+
+    public void exitEmergencyCallbackMode(){
+        mActivePhone.exitEmergencyCallbackMode();
+    }
+
+    public boolean isOtaSpNumber(String dialStr){
+        return mActivePhone.isOtaSpNumber(dialStr);
+    }
+
+    public void registerForCallWaiting(Handler h, int what, Object obj){
+        mActivePhone.registerForCallWaiting(h,what,obj);
+    }
+
+    public void unregisterForCallWaiting(Handler h){
+        mActivePhone.unregisterForCallWaiting(h);
+    }
+
+    public void registerForSignalInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForSignalInfo(h,what,obj);
+    }
+
+    public void unregisterForSignalInfo(Handler h) {
+        mActivePhone.unregisterForSignalInfo(h);
+    }
+
+    public void registerForDisplayInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForDisplayInfo(h,what,obj);
+    }
+
+    public void unregisterForDisplayInfo(Handler h) {
+        mActivePhone.unregisterForDisplayInfo(h);
+    }
+
+    public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
+        mActivePhone.setOnEcbModeExitResponse(h,what,obj);
+    }
+
+    public void unsetOnEcbModeExitResponse(Handler h){
+        mActivePhone.unsetOnEcbModeExitResponse(h);
     }
 }
-
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 070d233..f206d90 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -38,11 +38,18 @@
 import android.util.Config;
 import android.util.Log;
 
-import com.android.internal.telephony.CdmaInformationRecord;
-import com.android.internal.telephony.cdma.CdmaCallWaiting;
+import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.gsm.NetworkInfo;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.IccCardApplication;
+import com.android.internal.telephony.IccCardStatus;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.SmsResponse;
+import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
+import com.android.internal.telephony.cdma.CdmaInformationRecords;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
@@ -1063,10 +1070,11 @@
     sendBurstDtmf(String dtmfString, Message result) {
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BURST_DTMF, result);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
         rr.mp.writeString(dtmfString);
 
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                + " : " + dtmfString);
+
         send(rr);
     }
 
@@ -1331,28 +1339,32 @@
     }
 
     public void
-    acknowledgeLastIncomingSMS(boolean success, Message result) {
+    acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) {
         RILRequest rr
                 = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result);
 
-        rr.mp.writeInt(1);
+        rr.mp.writeInt(2);
         rr.mp.writeInt(success ? 1 : 0);
+        rr.mp.writeInt(cause);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                + " " + success + " " + cause);
 
         send(rr);
     }
 
     public void
-    acknowledgeLastIncomingCdmaSms(boolean success, Message result) {
+    acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) {
         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(39); //39 means other terminal problem; is not interpreted for success.
+        rr.mp.writeInt(cause);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                + " " + success + " " + cause);
 
         send(rr);
     }
@@ -1804,6 +1816,20 @@
         send(rr);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public void reportSmsMemoryStatus(boolean available, Message result) {
+        RILRequest rr = RILRequest.obtain(RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, result);
+        rr.mp.writeInt(1);
+        rr.mp.writeInt(available ? 1 : 0);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+                + requestToString(rr.mRequest) + ": " + available);
+
+        send(rr);
+    }
+
     //***** Private Methods
 
     private void sendScreenState(boolean on) {
@@ -1992,7 +2018,7 @@
             case RIL_REQUEST_CONFERENCE: ret =  responseVoid(p); break;
             case RIL_REQUEST_UDUB: ret =  responseVoid(p); break;
             case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret =  responseInts(p); break;
-            case RIL_REQUEST_SIGNAL_STRENGTH: ret =  responseInts(p); break;
+            case RIL_REQUEST_SIGNAL_STRENGTH: ret =  responseSignalStrength(p); break;
             case RIL_REQUEST_REGISTRATION_STATE: ret =  responseStrings(p); break;
             case RIL_REQUEST_GPRS_REGISTRATION_STATE: ret =  responseStrings(p); break;
             case RIL_REQUEST_OPERATOR: ret =  responseStrings(p); break;
@@ -2187,7 +2213,7 @@
             case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ret =  responseInts(p); break;
             case RIL_UNSOL_ON_USSD: ret =  responseStrings(p); break;
             case RIL_UNSOL_NITZ_TIME_RECEIVED: ret =  responseString(p); break;
-            case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseInts(p); break;
+            case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break;
             case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break;
             case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break;
             case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break;
@@ -2205,7 +2231,7 @@
             case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break;
             case RIL_UNSOL_CDMA_CALL_WAITING: ret = responseCdmaCallWaiting(p); break;
             case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: ret = responseInts(p); break;
-            case RIL_UNSOL_CDMA_INFO_REC: ret = responseCdmaInformationRecord(p); break;
+            case RIL_UNSOL_CDMA_INFO_REC: ret = responseCdmaInfoRec(p); break;
             case RIL_UNSOL_OEM_HOOK_RAW: ret = responseRaw(p); break;
 
             default:
@@ -2391,10 +2417,11 @@
                 break;
 
             case RIL_UNSOL_CALL_RING:
-                if (RILJ_LOGD) unsljLog(response);
+                if (RILJ_LOGD) unsljLogRet(response, ret);
 
                 if (mRingRegistrant != null) {
-                    mRingRegistrant.notifyRegistrant();
+                    mRingRegistrant.notifyRegistrant(
+                            new AsyncResult (null, ret, null));
                 }
                 break;
 
@@ -2434,13 +2461,6 @@
                 }
                 break;
 
-            case RIL_UNSOL_OEM_HOOK_RAW:
-                if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[])ret));
-                if (mUnsolOemHookRawRegistrant != null) {
-                    mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
-                }
-                break;
-
             case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE:
                 if (RILJ_LOGD) unsljLog(response);
 
@@ -2452,25 +2472,46 @@
             case RIL_UNSOL_CDMA_CALL_WAITING:
                 if (RILJ_LOGD) unsljLog(response);
 
-                if(mCallWaitingRegistrants != null) {
-                    mCallWaitingRegistrants.notifyRegistrants(new AsyncResult (null, ret, null));
+                if (mCallWaitingInfoRegistrants != null) {
+                    mCallWaitingInfoRegistrants.notifyRegistrants(
+                                        new AsyncResult (null, ret, null));
                 }
                 break;
 
             case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS:
-                if (RILJ_LOGD) unsljLog(response);
+                if (RILJ_LOGD) unsljLogRet(response, ret);
 
-                if (mOtaSessionRegistrants != null) {
-                    mOtaSessionRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
+                if (mOtaProvisionRegistrants != null) {
+                    mOtaProvisionRegistrants.notifyRegistrants(
+                                        new AsyncResult (null, ret, null));
                 }
                 break;
 
             case RIL_UNSOL_CDMA_INFO_REC:
-                if (RILJ_LOGD)
-                    unsljLog(response);
-                if (mInformationRecordsRegistrants != null) {
-                    mInformationRecordsRegistrants.notifyRegistrants(new AsyncResult(null, ret,
-                            null));
+                if (RILJ_LOGD) unsljLog(response);
+
+                CdmaInformationRecords infoRec = (CdmaInformationRecords) ret;
+                if (infoRec.isDispInfo) {
+                    if (mDisplayInfoRegistrants != null) {
+                        if (RILJ_LOGD) unsljLogRet(response, infoRec.cdmaDisplayInfoRecord);
+
+                        mDisplayInfoRegistrants.notifyRegistrants(
+                                new AsyncResult (null, infoRec.cdmaDisplayInfoRecord, null));
+                    }
+                }
+                if (infoRec.isSignInfo) {
+                    if (mSignalInfoRegistrants != null) {
+                        if (RILJ_LOGD) unsljLogRet(response, infoRec.cdmaSignalInfoRecord);
+                        mSignalInfoRegistrants.notifyRegistrants(
+                                new AsyncResult (null, infoRec.cdmaSignalInfoRecord, null));
+                    }
+                }
+                break;
+
+            case RIL_UNSOL_OEM_HOOK_RAW:
+                if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[])ret));
+                if (mUnsolOemHookRawRegistrant != null) {
+                    mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
                 }
                 break;
         }
@@ -2721,11 +2762,8 @@
             dc.als = p.readInt();
             voiceSettings = p.readInt();
             dc.isVoice = (0 == voiceSettings) ? false : true;
-
-            //dc.isVoicePrivacy = (0 != p.readInt());
             int voicePrivacy = p.readInt();
             dc.isVoicePrivacy = (0 != voicePrivacy);
-
             dc.number = p.readString();
             int np = p.readInt();
             dc.numberPresentation = DriverCall.presentationFromCLIP(np);
@@ -2834,15 +2872,48 @@
 
     private Object
     responseCDMA_BR_CNF(Parcel p) {
-        int numInts;
+        int numServiceCategories;
         int response[];
 
-        numInts = p.readInt();
+        numServiceCategories = p.readInt();
 
+        if (numServiceCategories == 0) {
+            int numInts;
+            numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES * CDMA_BSI_NO_OF_INTS_STRUCT + 1;
+            response = new int[numInts];
+
+            // Indicate that a zero length table was received
+            response[0] = 0; // TODO(Moto): This is very strange, please explain why.
+
+            // Loop over CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES set 'english' as
+            // default language and selection status to false
+            for (int i = 1; i < numInts; i += CDMA_BSI_NO_OF_INTS_STRUCT ) {
+                response[i + 0] = i / CDMA_BSI_NO_OF_INTS_STRUCT;
+                response[i + 1] = 1;
+                response[i + 2] = 0;
+            }
+        } else {
+            int numInts;
+            numInts = (numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT) + 1;
+            response = new int[numInts];
+
+            response[0] = numServiceCategories;
+            for (int i = 1 ; i < numInts; i++) {
+                 response[i] = p.readInt();
+             }
+        }
+
+        return response;
+    }
+
+    private Object
+    responseSignalStrength(Parcel p) {
+        int numInts = 7;
+        int response[];
+
+        /* TODO: Add SignalStrength class to match RIL_SignalStrength */
         response = new int[numInts];
-
-        response[0] = numInts;
-        for (int i = 1 ; i < numInts; i++) {
+        for (int i = 0 ; i < numInts ; i++) {
             response[i] = p.readInt();
         }
 
@@ -2850,105 +2921,81 @@
     }
 
     private Object
-    responseCdmaInformationRecord(Parcel p){
+    responseCdmaInfoRec(Parcel p) {
+        int infoRecordName;
+        CdmaInformationRecords records = new CdmaInformationRecords();
 
-        int num;
-        ArrayList<CdmaInformationRecord> response;
-
-        num = p.readInt();
-
-        response = new ArrayList<CdmaInformationRecord>(num);
-
-        for (int i = 0; i < num; i++) {
-            int name = p.readInt();
-            CdmaInformationRecord InfoRec = new CdmaInformationRecord(name);
-
-            char buffer[];
-            int length;
-            switch (name) {
-                case CdmaInformationRecord.RIL_CDMA_DISPLAY_INFO_REC:
-                case CdmaInformationRecord.RIL_CDMA_EXTENDED_DISPLAY_INFO_REC:
-                    length = p.readInt();
-                    buffer = new char[length];
-                    for (int j = 0; j < length; j++) {
-                        buffer[j] = (char)p.readInt();
-                    }
-                    InfoRec.createDisplayInfo(length, buffer);
+        int numberOfInfoRecs = p.readInt();
+        for (int i = 0; i < numberOfInfoRecs; i++) {
+            infoRecordName = p.readInt();
+            switch(infoRecordName) {
+                case CdmaInformationRecords.RIL_CDMA_DISPLAY_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_EXTENDED_DISPLAY_INFO_REC:
+                    records.setDispInfo(p.readString());
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC:
-                case CdmaInformationRecord.RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC:
-                case CdmaInformationRecord.RIL_CDMA_CONNECTED_NUMBER_INFO_REC:
-                    length = p.readInt();
-                    buffer = new char[length + 4];
-                    for (int j = 0; j < (length + 4); j++) {
-                        buffer[j] = (char)p.readInt();
-                    }
-                    InfoRec.createNumberInfo(length, buffer);
+                case CdmaInformationRecords.RIL_CDMA_SIGNAL_INFO_REC:
+                    records.setSignInfo(p.readInt(), p.readInt(), p.readInt(), p.readInt());
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_SIGNAL_INFO_REC:
-                    buffer = new char[4];
-                    for (int j = 0; j < 4; j++) {
-                        buffer[j] = (char)p.readInt();
-                    }
-                    InfoRec.createSignalInfo(buffer);
+                // InfoReocords with names as below aren't supported in AFW yet
+                case CdmaInformationRecords.RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_CONNECTED_NUMBER_INFO_REC:
+                    // TODO(Moto) implement
+                    p.readString(); // number
+                    p.readInt();    // number_type
+                    p.readInt();    // number_plan
+                    p.readInt();    // pi
+                    p.readInt();    // si
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_REDIRECTING_NUMBER_INFO_REC:
-                    length = p.readInt();
-                    buffer = new char[length + 4];
-                    int reason;
-                    for (int j = 0; j < (length + 4); j++) {
-                        buffer[j] = (char)p.readInt();
-                    }
-                    reason = p.readInt();
-                    InfoRec.createRedirectingNumberInfo(length, buffer, reason);
+                case CdmaInformationRecords.RIL_CDMA_REDIRECTING_NUMBER_INFO_REC:
+                    // TODO(Moto) implement
+                    p.readString(); // redirecting number
+                    p.readInt();    // number_type
+                    p.readInt();    // number_plan
+                    p.readInt();    // pi
+                    p.readInt();    // si
+                    p.readInt();    // reason
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_LINE_CONTROL_INFO_REC:
-                    buffer = new char[4];
-                    for (int j = 0; j < 4; j++) {
-                        buffer[j] = (char)p.readInt();
-                    }
-                    InfoRec.createLineControlInfo(buffer);
+                case CdmaInformationRecords.RIL_CDMA_LINE_CONTROL_INFO_REC:
+                    // TODO(Moto) implement
+                    p.readInt();    // PolarityIncluded
+                    p.readInt();    // Toggle
+                    p.readInt();    // Reverse
+                    p.readInt();    // PowerDenial
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_T53_CLIR_INFO_REC:
-                    char ch = (char)p.readInt();
-                    InfoRec.createT53ClirInfo(ch);
+                case CdmaInformationRecords.RIL_CDMA_T53_CLIR_INFO_REC:
+                    // TODO(Moto) implement
+                    p.readInt();    // Cause
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_T53_RELEASE_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC:
+                    // TODO(Moto) implement
+                    p.readInt();    // upLink
+                    p.readInt();    // downLink
                     break;
-
-                case CdmaInformationRecord.RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC:
-                    char ul = (char)p.readInt();
-                    char dl = (char)p.readInt();
-                    InfoRec.createT53AudioControlInfo(ul, dl);
-                    break;
-
+                case CdmaInformationRecords.RIL_CDMA_T53_RELEASE_INFO_REC:
+                    // TODO(Moto) implement unknown fall through
                 default:
-                    break;
+                    throw new RuntimeException("RIL_UNSOL_CDMA_INFO_REC: unsupported record. Got "
+                                                + records.recordToString(infoRecordName) + " ");
             }
-            response.add(InfoRec);
         }
-
-        return response;
+        return records;
     }
 
     private Object
-    responseCdmaCallWaiting(Parcel p){
-        CdmaCallWaiting response = new CdmaCallWaiting();
-        response.number = p.readString();
-        response.numberPresentation = p.readInt();
-        response.name = p.readString();
-        response.signalInfoRecord.isPresent =  p.readInt() == 0 ? false : true;
-        response.signalInfoRecord.signalType = p.readInt();
-        response.signalInfoRecord.alertPitch = p.readInt();
-        response.signalInfoRecord.signalCode = p.readInt();
+    responseCdmaCallWaiting(Parcel p) {
+        CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification();
 
-        return response;
+        notification.number = p.readString();
+        notification.numberPresentation = p.readInt();
+        notification.name = p.readString();
+        notification.namePresentation = notification.numberPresentation;
+        notification.isPresent = p.readInt();
+        notification.signalType = p.readInt();
+        notification.alertPitch = p.readInt();
+        notification.signal = p.readInt();
+
+        return notification;
     }
 
     private Object
@@ -3104,16 +3151,16 @@
             case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL";
             case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
             case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
-            case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED";
-            case RIL_UNSOL_OEM_HOOK_RAW: return "RIL_UNSOL_OEM_HOOK_RAW";
             case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: return "UNSOL_RESPONSE_SIM_STATUS_CHANGED";
             case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: return "UNSOL_RESPONSE_CDMA_NEW_SMS";
             case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: return "UNSOL_RESPONSE_NEW_BROADCAST_SMS";
             case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: return "UNSOL_CDMA_RUIM_SMS_STORAGE_FULL";
+            case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "UNSOL_RESTRICTED_STATE_CHANGED";
             case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: return "UNSOL_ENTER_EMERGENCY_CALLBACK_MODE";
             case RIL_UNSOL_CDMA_CALL_WAITING: return "UNSOL_CDMA_CALL_WAITING";
             case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS";
             case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC";
+            case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW";
             default: return "<unknown reponse>";
         }
     }
@@ -3255,10 +3302,7 @@
         send(rr);
     }
 
-    /**
-     * TODO(Teleca): configValuesArray is represented as a RIL_BroadcastSMSConfig
-     * so we think this should be a class with the appropriate parameters not an array?
-     */
+    // TODO: Change the configValuesArray to a RIL_BroadcastSMSConfig
     public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) {
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, response);
 
@@ -3286,8 +3330,7 @@
      * {@inheritDoc}
      */
     public void exitEmergencyCallbackMode(Message response) {
-        RILRequest rr
-                = RILRequest.obtain(RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, response);
+        RILRequest rr = RILRequest.obtain(RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, response);
 
         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 44c863b..26995ef 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -222,6 +222,7 @@
     int RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE = 99;
     int RIL_REQUEST_GET_SMSC_ADDRESS = 100;
     int RIL_REQUEST_SET_SMSC_ADDRESS = 101;
+    int RIL_REQUEST_REPORT_SMS_MEMORY_STATUS = 102;
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index d055c311..12808ce 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -20,6 +20,7 @@
 import android.app.PendingIntent;
 import android.app.AlertDialog;
 import android.app.PendingIntent.CanceledException;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -32,6 +33,7 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PowerManager;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.provider.Settings;
@@ -128,6 +130,15 @@
 
     private SmsTracker mSTracker;
 
+    /** Wake lock to ensure device stays awake while dispatching the SMS intent. */
+    private PowerManager.WakeLock mWakeLock;
+
+    /**
+     * Hold the wake lock for 5 seconds, which should be enough time for
+     * any receiver(s) to grab its own wake lock.
+     */
+    private final int WAKE_LOCK_TIMEOUT = 5000;
+
     private static SmsMessage mSmsMessage;
     private static SmsMessageBase mSmsMessageBase;
     private SmsMessageBase.SubmitPduBase mSubmitPduBase;
@@ -196,14 +207,16 @@
 
     protected SMSDispatcher(PhoneBase phone) {
         mPhone = phone;
-        mWapPush = new WapPushOverSms(phone);
+        mWapPush = new WapPushOverSms(phone, this);
         mContext = phone.getContext();
         mResolver = mContext.getContentResolver();
         mCm = phone.mCM;
         mSTracker = null;
 
+        createWakelock();
+
         int check_period = Settings.Gservices.getInt(mResolver,
-                Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
+                Settings.Gservices.SMS_OUTGOING_CHECK_INTERVAL_MS,
                 DEFAULT_SMS_CHECK_PERIOD);
         int max_count = Settings.Gservices.getInt(mResolver,
                 Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT,
@@ -257,16 +270,17 @@
 
             ar = (AsyncResult) msg.obj;
 
-                // FIXME only acknowledge on store
-            acknowledgeLastIncomingSms(true, null);
-
             if (ar.exception != null) {
                 Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception);
                 return;
             }
 
             sms = (SmsMessage) ar.result;
-            dispatchMessage(sms.mWrappedSmsMessage);
+            try {
+                dispatchMessage(sms.mWrappedSmsMessage);
+            } catch (RuntimeException ex) {
+                acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null);
+            }
 
             break;
 
@@ -310,6 +324,28 @@
         }
     }
 
+    private void createWakelock() {
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher");
+        mWakeLock.setReferenceCounted(true);
+    }
+
+    /**
+     * Grabs a wake lock and sends intent as an ordered broadcast.
+     * The resultReceiver will check for errors and ACK/NACK back
+     * to the RIL.
+     *
+     * @param intent intent to broadcast
+     * @param permission Receivers are required to have this permission
+     */
+    void dispatch(Intent intent, String permission) {
+        // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
+        // receivers time to take their own wake locks.
+        mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
+        mContext.sendOrderedBroadcast(intent, permission, mResultReceiver,
+                this, Activity.RESULT_OK, null, null);
+    }
+
     /**
      * Called when SIM_FULL message is received from the RIL.  Notifies interested
      * parties that SIM storage for SMS messages is full.
@@ -317,7 +353,8 @@
     private void handleIccFull(){
         // broadcast SIM_FULL intent
         Intent intent = new Intent(Intents.SIM_FULL_ACTION);
-        mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS");
+        mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
+        mContext.sendBroadcast(intent, "android.permission.RECEIVE_SMS");
     }
 
     /**
@@ -454,6 +491,7 @@
                     values.put("destination_port", portAddrs.destPort);
                 }
                 mResolver.insert(mRawUri, values);
+                acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null);
                 return;
             }
 
@@ -475,7 +513,9 @@
             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.
+            // TODO:  Would OUT_OF_MEMORY be more appropriate?
+            acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null);
+            return;
         } finally {
             if (cursor != null) cursor.close();
         }
@@ -519,8 +559,7 @@
     protected void dispatchPdus(byte[][] pdus) {
         Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
         intent.putExtra("pdus", pdus);
-        mPhone.getContext().sendBroadcast(
-                intent, "android.permission.RECEIVE_SMS");
+        dispatch(intent, "android.permission.RECEIVE_SMS");
     }
 
     /**
@@ -533,8 +572,7 @@
         Uri uri = Uri.parse("sms://localhost:" + port);
         Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
         intent.putExtra("pdus", pdus);
-        mPhone.getContext().sendBroadcast(
-                intent, "android.permission.RECEIVE_SMS");
+        dispatch(intent, "android.permission.RECEIVE_SMS");
     }
 
 
@@ -698,9 +736,11 @@
     /**
      * Send an acknowledge message.
      * @param success indicates that last message was successfully received.
+     * @param result result code indicating any error
      * @param response callback message sent when operation completes.
      */
-    protected abstract void acknowledgeLastIncomingSms(boolean success, Message response);
+    protected abstract void acknowledgeLastIncomingSms(boolean success,
+            int result, Message response);
 
     /**
      * Check if a SmsTracker holds multi-part Sms
@@ -751,4 +791,17 @@
                 }
             }
         };
+
+        private BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                int rc = getResultCode();
+                boolean success = (rc == Activity.RESULT_OK) || (rc == Intents.RESULT_SMS_HANDLED);
+
+                // For a multi-part message, this only ACKs the last part.
+                // Previous parts were ACK'd as they were received.
+                acknowledgeLastIncomingSms(success, rc, null);
+            }
+
+        };
 }
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 31bb652..4d32c35 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -312,7 +312,9 @@
     }
 
     protected void parseMessageBody() {
-        if (originatingAddress.couldBeEmailGateway()) {
+        // originatingAddress could be null if this message is from a status
+        // report.
+        if (originatingAddress != null && originatingAddress.couldBeEmailGateway()) {
             extractEmailAddressFromMessageBody();
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 91aa34e..c78ceae 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -54,8 +54,10 @@
     public static final String ACTION_RADIO_TECHNOLOGY_CHANGED 
             = "android.intent.action.RADIO_TECHNOLOGY";
     /**
-     * <p>Broadcast Action: The emergency callback mode is entered.
-     *
+     * <p>Broadcast Action: The emergency callback mode is changed.
+     * <ul>
+     *   <li><em>phoneinECMState</em> - A boolean value,true=phone in ECM, false=ECM off</li>
+     * </ul>
      * <p class="note">
      * You can <em>not</em> receive this through components declared
      * in manifests, only by explicitly registering for it with
@@ -65,8 +67,8 @@
      * <p class="note">
      * Requires no permission.
      */
-    public static final String ACTION_EMERGENCY_CALLBACK_MODE_ENTERED
-            = "android.intent.action.EMERGENCY_CALLBACK_MODE";
+    public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
+            = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
     /**
      * Broadcast Action: The phone's signal strength has changed. The intent will have the
      * following extra values:</p>
@@ -179,4 +181,28 @@
      */
     public static final String ACTION_NETWORK_SET_TIMEZONE
             = "android.intent.action.NETWORK_SET_TIMEZONE";
+
+    /**
+     * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
+     * <p class="note">.
+     */
+    // TODO(Moto): What is the use case, who is interested in this?
+    public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
+            = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
+
+     /**
+     * Broadcast Action: The MDN changed during the CDMA OTA Process
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>mdn</em> - An Integer of the updated MDN number.</li>
+     * </ul>
+     *
+     * <p class="note">
+     */
+    // TODO(Moto): Generally broadcast intents are for use to allow entities which
+    // may not know about each other to "communicate". This seems quite specific
+    // and maybe using the registrant style would be better.
+    public static final String ACTION_CDMA_OTA_MDN_CHANGED
+            = "android.intent.action.ACTION_MDN_STATE_CHANGED";
+
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 453185f..4e8950f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -98,4 +98,7 @@
      */
     static String PROPERTY_DATA_NETWORK_TYPE = "gsm.network.type";
 
+    /** Indicate if phone is in emergency callback mode */
+    static final String PROPERTY_INECM_MODE = "ril.cdma.inecmmode";
+
 }
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index 98899c9..c851bc1 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.PowerManager;
 import android.provider.Telephony.Sms.Intents;
 import android.util.Config;
 import android.util.Log;
@@ -34,7 +33,7 @@
 
     private final Context mContext;
     private WspTypeDecoder pduDecoder;
-    private PowerManager.WakeLock mWakeLock;
+    private SMSDispatcher mSmsDispatcher;
 
     /**
      * Hold the wake lock for 5 seconds, which should be enough time for 
@@ -42,10 +41,9 @@
      */
     private final int WAKE_LOCK_TIMEOUT = 5000;
 
-    public WapPushOverSms(Phone phone) {
-
+    public WapPushOverSms(Phone phone, SMSDispatcher smsDispatcher) {
+        mSmsDispatcher = smsDispatcher;
         mContext = phone.getContext();
-        createWakelock();
     }
 
     /**
@@ -184,7 +182,7 @@
         intent.putExtra("pduType", pduType);
         intent.putExtra("data", data);
 
-        sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
+        mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH");
     }
 
     private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) {
@@ -194,7 +192,7 @@
         intent.putExtra("pduType", pduType);
         intent.putExtra("data", pdu);
 
-        sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
+        mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH");
     }
 
     private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) {
@@ -209,20 +207,7 @@
         intent.putExtra("pduType", pduType);
         intent.putExtra("data", data);
 
-        sendBroadcast(intent, "android.permission.RECEIVE_MMS");
-    }
-
-    private void createWakelock() {
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WapPushOverSms");
-        mWakeLock.setReferenceCounted(true);
-    }
-
-    private void sendBroadcast(Intent intent, String permission) {
-        // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
-        // receivers time to take their own wake locks.
-        mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
-        mContext.sendBroadcast(intent, permission);
+        mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_MMS");
     }
 }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 03f7f98..7ba9951 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -35,6 +35,7 @@
 import android.util.Log;
 
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_INECM_MODE;
 
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CommandsInterface;
@@ -54,9 +55,9 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 
-import java.util.ArrayList;
 import java.util.List;
-
+import java.util.Timer;
+import java.util.TimerTask;
 /**
  * {@hide}
  */
@@ -83,8 +84,21 @@
 
     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
     private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
+
+    // mECMExitRespRegistrant is informed after the phone has been exited
+    //the emergency callback mode
+    //keep track of if phone is in emergency callback mode
+    private boolean mIsPhoneInECMState;
+    private Registrant mECMExitRespRegistrant;
     private String mEsn;
     private String mMeid;
+    
+    // A runnable which is used to automatically exit from ECM after a period of time.
+    private Runnable mExitEcmRunnable = new Runnable() {
+        public void run() {
+            exitEmergencyCallbackMode();
+        }
+    };
 
     Registrant mPostDialHandler;
 
@@ -122,13 +136,16 @@
         mCM.setOnCallRing(h, EVENT_CALL_RING, null);
         mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
         mCM.registerForNVReady(h, EVENT_NV_READY, null);
-        mCM.registerForCdmaCallWaiting(h,EVENT_CDMA_CALL_WAITING,null);
-        mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE, null);
+        mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
 
 
         //Change the system setting
         SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
                 new Integer(RILConstants.CDMA_PHONE).toString());
+
+        // TODO(Moto): Is this needed to handle phone crashes and/or power cycling?
+        String inEcm=SystemProperties.get(PROPERTY_INECM_MODE, "false");
+        mIsPhoneInECMState = inEcm.equals("true");
     }
 
     public void dispose() {
@@ -143,7 +160,7 @@
             mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
             mCM.unSetOnSuppServiceNotification(h);
             mCM.unSetOnCallRing(h);
-            mCM.unregisterForCdmaCallWaiting(h);
+
 
             //Force all referenced classes to unregister their former registered events
             mCT.dispose();
@@ -232,7 +249,7 @@
     public DataActivityState getDataActivityState() {
         DataActivityState ret = DataActivityState.NONE;
 
-        if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) {
+        if (mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
 
             switch (mDataConnection.getActivity()) {
                 case DATAIN:
@@ -367,11 +384,11 @@
     }
 
     public String getLine1Number() {
-        return mRuimRecords.getMdnNumber();
+        return mSST.getMdnNumber();
     }
 
-    public String getMin() {
-        return mRuimRecords.getMin();
+    public String getCdmaMIN() {
+        return mSST.getCdmaMin();
     }
 
     public void getCallWaiting(Message onComplete) {
@@ -434,7 +451,7 @@
     }
 
     public void setOnPostDialCharacter(Handler h, int what, Object obj) {
-        Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA");
+        mPostDialHandler = new Registrant(h, what, obj);
     }
 
     public boolean handlePinMmi(String dialString) {
@@ -478,6 +495,30 @@
         mDataConnection.setDataOnRoamingEnabled(enable);
     }
 
+    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
+        mCM.registerForCdmaOtaProvision(h, what, obj);
+    }
+
+    public void unregisterForCdmaOtaStatusChange(Handler h) {
+        mCM.unregisterForCdmaOtaProvision(h);
+    }
+
+    public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
+        mECMExitRespRegistrant = new Registrant (h, what, obj);
+    }
+
+    public void unsetOnEcbModeExitResponse(Handler h) {
+        mECMExitRespRegistrant.clear();
+    }
+
+    public void registerForCallWaiting(Handler h, int what, Object obj) {
+        Log.e(LOG_TAG, "method registerForCallWaiting is NOT yet supported in CDMA");
+    }
+
+    public void unregisterForCallWaiting(Handler h) {
+        Log.e(LOG_TAG, "method unregisterForCallWaiting is NOT yet supported in CDMA");
+    }
+
     public String getIpAddress(String apnType) {
         return mDataConnection.getIpAddress();
     }
@@ -504,8 +545,7 @@
              // already been called
 
              ret = DataState.DISCONNECTED;
-        } else if (mSST.getCurrentCdmaDataConnectionState()
-                == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) {
+        } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
             // If we're out of service, open TCP sockets may still work
             // but no data will flow
             ret = DataState.DISCONNECTED;
@@ -565,7 +605,7 @@
         mCM.stopDtmf(null);
     }
 
-    public void sendBurstDtmf(String dtmfString) {
+    public void sendBurstDtmf(String dtmfString, Message onComplete) {
         boolean check = true;
         for (int itr = 0;itr < dtmfString.length(); itr++) {
             if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
@@ -576,7 +616,7 @@
             }
         }
         if ((mCT.state ==  Phone.State.OFFHOOK)&&(check)) {
-            mCM.sendBurstDtmf(dtmfString, null);
+            mCM.sendBurstDtmf(dtmfString, onComplete);
         }
      }
 
@@ -593,7 +633,7 @@
     }
 
     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
-        Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
+        Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA");
     }
 
     public void enableLocationUpdates() {
@@ -630,7 +670,14 @@
         //TODO: Where can we get this value has to be clarified with QC
         //return mSIMRecords.getVoiceMailNumber();
 //      throw new RuntimeException();
-        return "12345";
+        return "*86";
+    }
+
+    /* Returns Number of Voicemails
+     * @hide
+     */
+    public int getCountVoiceMessages() {
+        return mRuimRecords.getCountVoiceMessages();
     }
 
     public String getVoiceMailAlphaTag() {
@@ -648,7 +695,15 @@
     }
 
     public boolean enableDataConnectivity() {
-        return mDataConnection.setDataEnabled(true);
+
+        // block data activities when phone is in emergency callback mode
+        if (mIsPhoneInECMState) {
+            Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
+            ActivityManagerNative.broadcastStickyIntent(intent, null);
+            return false;
+        } else {
+            return mDataConnection.setDataEnabled(true);
+        }
     }
 
     public void disableLocationUpdates() {
@@ -691,7 +746,7 @@
         return null;
     }
 
-    /**
+   /**
      * Notify any interested party of a Phone state change.
      */
     /*package*/ void notifyPhoneStateChanged() {
@@ -736,6 +791,13 @@
         mUnknownConnectionRegistrants.notifyResult(this);
     }
 
+    void sendEmergencyCallbackModeChange(){
+        //Send an Intent
+        Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInECMState);
+        ActivityManagerNative.broadcastStickyIntent(intent,null);
+    }
+
     /*package*/ void
     updateMessageWaitingIndicator(boolean mwi) {
         // this also calls notifyMessageWaitingIndicator()
@@ -761,6 +823,51 @@
          mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, fc, null));
     }
 
+
+    @Override
+    public void exitEmergencyCallbackMode() {
+        // Send a message which will invoke handleExitEmergencyCallbackMode
+        mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
+    }
+
+    private void handleEnterEmergencyCallbackMode(Message msg) {
+        Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received");
+        // if phone is not in ECM mode, and it's changed to ECM mode
+        if (mIsPhoneInECMState == false) {
+            mIsPhoneInECMState = true;
+            // notify change
+            sendEmergencyCallbackModeChange();
+            setSystemProperty(PROPERTY_INECM_MODE, "true");
+    
+            // Post this runnable so we will automatically exit
+            // if no one invokes exitEmergencyCallbackMode() directly.
+            // TODO(Moto): Get the delay a property so it can be adjusted
+            long delayInMillis = 300000; // 30,000 millis == 5 minutes
+            h.postDelayed(mExitEcmRunnable, delayInMillis);
+        }
+    }
+
+    private void handleExitEmergencyCallbackMode(Message msg) {
+        Log.d(LOG_TAG, "Event EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE Received");
+        AsyncResult ar = (AsyncResult)msg.obj;
+
+        // Remove pending exit ECM runnable, if any
+        h.removeCallbacks(mExitEcmRunnable);
+
+        if (mECMExitRespRegistrant != null) {
+            mECMExitRespRegistrant.notifyRegistrant(ar);
+        }
+        // if exiting ecm success
+        if (ar.exception == null) {
+            if (mIsPhoneInECMState) {
+                mIsPhoneInECMState = false;
+                setSystemProperty(PROPERTY_INECM_MODE, "false");
+            }
+            // send an Intent
+            sendEmergencyCallbackModeChange();
+        }
+    }
+
     //***** Inner Classes
     class MyHandler extends Handler {
         MyHandler() {
@@ -770,6 +877,7 @@
             super(l);
         }
 
+        @Override
         public void handleMessage(Message msg) {
             AsyncResult ar;
             Message     onComplete;
@@ -806,12 +914,16 @@
                 }
                 break;
 
-                case EVENT_EMERGENCY_CALLBACK_MODE: {
-                    Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received");
-                    Intent intent =
-                        new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_ENTERED);
-                    ActivityManagerNative.broadcastStickyIntent(intent, null);
+                case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
+                    handleEnterEmergencyCallbackMode(msg);
                 }
+                break;
+
+                case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
+                    handleExitEmergencyCallbackMode(msg);
+                }
+                break;
+
                 case EVENT_RUIM_RECORDS_LOADED:{
                     Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
                 }
@@ -852,11 +964,7 @@
                         Log.d(LOG_TAG, "ERI read, notify registrants");
                         mEriFileLoadedRegistrants.notifyRegistrants();
                     }
-                }
-                break;
-
-                case EVENT_CDMA_CALL_WAITING:{
-                    Log.d(LOG_TAG, "Event EVENT_CDMA_CALL_WAITING Received");
+                    setSystemProperty(PROPERTY_INECM_MODE,"false");
                 }
                 break;
 
@@ -867,26 +975,26 @@
         }
     }
 
-     /**
-      * Retrieves the PhoneSubInfo of the CDMAPhone
-      */
-     public PhoneSubInfo getPhoneSubInfo(){
+    /**
+     * Retrieves the PhoneSubInfo of the CDMAPhone
+     */
+    public PhoneSubInfo getPhoneSubInfo() {
         return mSubInfo;
-     }
+    }
 
-     /**
-      * Retrieves the IccSmsInterfaceManager of the CDMAPhone
-      */
-     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
-         return mRuimSmsInterfaceManager;
-     }
+    /**
+     * Retrieves the IccSmsInterfaceManager of the CDMAPhone
+     */
+    public IccSmsInterfaceManager getIccSmsInterfaceManager() {
+        return mRuimSmsInterfaceManager;
+    }
 
-     /**
-      * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
-      */
-     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
-         return mRuimPhoneBookInterfaceManager;
-     }
+    /**
+     * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
+     */
+    public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() {
+        return mRuimPhoneBookInterfaceManager;
+    }
 
     public void registerForNvLoaded(Handler h, int what, Object obj) {
         Registrant r = new Registrant (h, what, obj);
@@ -906,156 +1014,151 @@
         mEriFileLoadedRegistrants.remove(h);
     }
 
-     // override for allowing access from other classes of this package
-     /**
-      * {@inheritDoc}
-      */
-     public final void setSystemProperty(String property, String value) {
-         super.setSystemProperty(property, value);
-     }
-
-     /**
-      * {@inheritDoc}
-      */
-     public Handler getHandler(){
-         return h;
-     }
-
-     /**
-      * {@inheritDoc}
-      */
-     public IccFileHandler getIccFileHandler(){
-         return this.mIccFileHandler;
-     }
-
-     /**
-      * Set the TTY mode of the CDMAPhone
-      */
-     public void setTTYMode(int ttyMode, Message onComplete) {
-         this.mCM.setTTYMode(ttyMode, onComplete);
-}
-
-     /**
-      * Queries the TTY mode of the CDMAPhone
-      */
-     public void queryTTYMode(Message onComplete) {
-         this.mCM.queryTTYMode(onComplete);
-     }
-
-     /**
-      * Sends Exit EmergencyCallbackMode Exit request on CDMAPhone
-      */
-     public void exitEmergencyCallbackMode(Message onComplete) {
-         this.mCM.exitEmergencyCallbackMode(onComplete);
-     }
-
-     /**
-      * Activate or deactivate cell broadcast SMS.
-      *
-      * @param activate
-      *            0 = activate, 1 = deactivate
-      * @param response
-      *            Callback message is empty on completion
-      */
-     public void activateCellBroadcastSms(int activate, Message response) {
-         mSMS.activateCellBroadcastSms(activate, response);
-     }
-
-     /**
-      * Query the current configuration of cdma cell broadcast SMS.
-      *
-      * @param response
-      *            Callback message is empty on completion
-      */
-     public void getCellBroadcastSmsConfig(Message response){
-         mSMS.getCellBroadcastSmsConfig(response);
-     }
-
-     /**
-      * Configure cdma cell broadcast SMS.
-      *
-      * @param response
-      *            Callback message is empty on completion
-      */
-     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
-         mSMS.setCellBroadcastConfig(configValuesArray, response);
-     }
-
-     public void registerForOtaSessionStatus(Handler h, int what, Object obj){
-         mCM.registerForOtaSessionStatus(h, what, obj);
-     }
-
-     public void unregisterForOtaSessionStatus(Handler h){
-         mCM.unregisterForOtaSessionStatus(h);
-     }
-
-/**
- * TODO(Teleca): The code in getCdmaEriIconIndex, getCdmaEriIconMode & getCdmaEriText share a
- * lot of logic, refactor.
- */
+    // override for allowing access from other classes of this package
     /**
-     * Returns the CDMA ERI icon index to display,
-     * it returns 1, EriInfo.ROAMING_INDICATOR_OFF, in case there is no icon to display
+     * {@inheritDoc}
      */
+    public final void setSystemProperty(String property, String value) {
+        super.setSystemProperty(property, value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Handler getHandler() {
+        return h;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public IccFileHandler getIccFileHandler() {
+        return this.mIccFileHandler;
+    }
+
+    /**
+     * Set the TTY mode of the CDMAPhone
+     */
+    public void setTTYMode(int ttyMode, Message onComplete) {
+        this.mCM.setTTYMode(ttyMode, onComplete);
+    }
+
+    /**
+     * Queries the TTY mode of the CDMAPhone
+     */
+    public void queryTTYMode(Message onComplete) {
+        this.mCM.queryTTYMode(onComplete);
+    }
+
+    /**
+     * Activate or deactivate cell broadcast SMS.
+     *
+     * @param activate 0 = activate, 1 = deactivate
+     * @param response Callback message is empty on completion
+     */
+    public void activateCellBroadcastSms(int activate, Message response) {
+        mSMS.activateCellBroadcastSms(activate, response);
+    }
+
+    /**
+     * Query the current configuration of cdma cell broadcast SMS.
+     *
+     * @param response Callback message is empty on completion
+     */
+    public void getCellBroadcastSmsConfig(Message response) {
+        mSMS.getCellBroadcastSmsConfig(response);
+    }
+
+    /**
+     * Configure cdma cell broadcast SMS.
+     *
+     * @param response Callback message is empty on completion
+     */
+    public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
+        mSMS.setCellBroadcastConfig(configValuesArray, response);
+    }
+
+    public static final String IS683A_FEATURE_CODE = "*228" ;
+    public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ;
+    public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ;
+    public static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
+
+    private static final int IS683_CONST_800MHZ_A_BAND = 0;
+    private static final int IS683_CONST_800MHZ_B_BAND = 1;
+    private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
+    private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
+    private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
+    private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
+    private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
+    private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
+
+    private boolean isIs683OtaSpDialStr(String dialStr) {
+        int sysSelCodeInt;
+        boolean isOtaspDialString = false;
+        int dialStrLen = dialStr.length();
+
+        if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
+            if (dialStr.equals(IS683A_FEATURE_CODE)) {
+                isOtaspDialString = true;
+            }
+        } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0,
+                                          IS683A_FEATURE_CODE_NUM_DIGITS) == true)
+                    && (dialStrLen >=
+                        (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
+            StringBuilder sb = new StringBuilder(dialStr);
+            // Separate the System Selection Code into its own string
+            char[] sysSel = new char[2];
+            sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET);
+            sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0);
+
+            if ((PhoneNumberUtils.isISODigit(sysSel[0]))
+                    && (PhoneNumberUtils.isISODigit(sysSel[1]))) {
+                String sysSelCode = new String(sysSel);
+                sysSelCodeInt = Integer.parseInt((String)sysSelCode);
+                switch (sysSelCodeInt) {
+                    case IS683_CONST_800MHZ_A_BAND:
+                    case IS683_CONST_800MHZ_B_BAND:
+                    case IS683_CONST_1900MHZ_A_BLOCK:
+                    case IS683_CONST_1900MHZ_B_BLOCK:
+                    case IS683_CONST_1900MHZ_C_BLOCK:
+                    case IS683_CONST_1900MHZ_D_BLOCK:
+                    case IS683_CONST_1900MHZ_E_BLOCK:
+                    case IS683_CONST_1900MHZ_F_BLOCK:
+                        isOtaspDialString = true;
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+        return isOtaspDialString;
+    }
+
+     /**
+      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
+      * OTASP dial string.
+      *
+      * @param dialStr the number to look up.
+      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
+      */
+    @Override
+     public  boolean isOtaSpNumber(String dialStr){
+         boolean isOtaSpNum = false;
+         if(dialStr != null){
+             isOtaSpNum=isIs683OtaSpDialStr(dialStr);
+             if(isOtaSpNum == false){
+             //TO DO:Add carrier specific OTASP number detection here.
+             }
+         }
+         return isOtaSpNum;
+     }
+
     @Override
     public int getCdmaEriIconIndex() {
         int roamInd = getServiceState().getCdmaRoamingIndicator();
         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
-        int ret = -1;
-
-        switch (roamInd) {
-            // Handling the standard roaming indicator (non-ERI)
-            case EriInfo.ROAMING_INDICATOR_ON:
-            case EriInfo.ROAMING_INDICATOR_OFF:
-            case EriInfo.ROAMING_INDICATOR_FLASH:
-                Log.d(LOG_TAG, "Using Standard Roaming Indicator (non-ERI): " + roamInd);
-                ret = roamInd;
-            break;
-
-            // Handling the Enhanced Roaming Indicator (roamInd > 2)
-            default:
-                if (!mEriManager.isEriFileLoaded()) {
-                    /**
-                     * TODO(Teleca): What is going on here? Conditionals on the variable being
-                     * switched? Seems unreasonably confusing... Especially since the above comment
-                     * indicates this should always be true... If we used explicit returns, the
-                     * switch could be used to filter specific cases for early bail, and the rest
-                     * could then be dealt with outside the switch...
-                     */
-
-                    if(defRoamInd > 2) {
-                        Log.d(LOG_TAG, "ERI File not loaded, using: "
-                                + EriInfo.ROAMING_INDICATOR_FLASH);
-                        ret = EriInfo.ROAMING_INDICATOR_FLASH;
-                    } else {
-                        Log.d(LOG_TAG, "ERI File not loaded, using: " + defRoamInd);
-                        ret = defRoamInd;
-                    }
-                } else if (mEriManager.getEriInfo(roamInd) == null) {
-                    if(mEriManager.getEriInfo(defRoamInd) == null) {
-/**
- * TODO(Teleca): Why the redundant code? Especially since it results in this very strange looking
- * almost-identical conditional... How about calling each version of mEriManager.getEriInfo just
- * once, and conditionalizing on the results..
- */
-                        Log.e(LOG_TAG, "Error: ERI entry: " + roamInd
-                                + " not present, defRoamInd: " + defRoamInd
-                                + " not defined in ERI file");
-                        ret = EriInfo.ROAMING_INDICATOR_ON;
-                    } else {
-                        int iconIndex = mEriManager.getEriInfo(defRoamInd).mIconIndex;
-                        Log.d(LOG_TAG, "ERI entry " + roamInd + " not present, using icon: "
-                                + iconIndex);
-                        ret = iconIndex;
-                    }
-                } else {
-                    int iconIndex = mEriManager.getEriInfo(roamInd).mIconIndex;
-                    Log.d(LOG_TAG, "Using ERI icon: " + iconIndex);
-                    ret = iconIndex;
-                }
-            break;
-        }
-        return ret;
+        return mEriManager.getCdmaEriIconIndex(roamInd, defRoamInd);
     }
 
     /**
@@ -1067,60 +1170,7 @@
     public int getCdmaEriIconMode() {
         int roamInd = getServiceState().getCdmaRoamingIndicator();
         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
-        int ret = -1;
-
-        switch (roamInd) {
-            // Handling the standard roaming indicator (non-ERI)
-            case EriInfo.ROAMING_INDICATOR_ON:
-            case EriInfo.ROAMING_INDICATOR_OFF:
-                Log.d(LOG_TAG, "Using Standard Roaming Indicator (non-ERI): normal");
-                ret = EriInfo.ROAMING_ICON_MODE_NORMAL;
-            break;
-
-            case EriInfo.ROAMING_INDICATOR_FLASH:
-                Log.d(LOG_TAG, "Using Standard Roaming Indicator (non-ERI): flashing");
-                ret = EriInfo.ROAMING_ICON_MODE_FLASH;
-            break;
-
-            // Handling the Enhanced Roaming Indicator (roamInd > 2)
-            default:
-                if (!mEriManager.isEriFileLoaded()) {
-                    if(defRoamInd > 2) {
-                        Log.d(LOG_TAG, "ERI File not loaded, defRoamInd > 2, flashing");
-                        ret = EriInfo.ROAMING_ICON_MODE_FLASH;
-                    } else {
-                        switch (defRoamInd) {
-                            // Handling the standard roaming indicator (non-ERI)
-                            case EriInfo.ROAMING_INDICATOR_ON:
-                            case EriInfo.ROAMING_INDICATOR_OFF:
-                                Log.d(LOG_TAG, "ERI File not loaded, normal");
-                                ret = EriInfo.ROAMING_ICON_MODE_NORMAL;
-                            break;
-
-                            case EriInfo.ROAMING_INDICATOR_FLASH:
-                                Log.d(LOG_TAG, "ERI File not loaded, normal");
-                                ret = EriInfo.ROAMING_ICON_MODE_FLASH;
-                            break;
-                        }
-                    }
-                } else if (mEriManager.getEriInfo(roamInd) == null) {
-                    if(mEriManager.getEriInfo(defRoamInd) == null) {
-                        Log.e(LOG_TAG, "Error: defRoamInd not defined in ERI file, normal");
-                        ret =  EriInfo.ROAMING_ICON_MODE_NORMAL;
-                    } else {
-                        int mode = mEriManager.getEriInfo(defRoamInd).mIconMode;
-                        Log.d(LOG_TAG, "ERI entry " + roamInd + " not present, icon  mode: "
-                                + mode);
-                        ret = mode;
-                    }
-                } else {
-                    int mode = mEriManager.getEriInfo(roamInd).mIconMode;
-                    Log.d(LOG_TAG, "Using ERI icon mode: " + mode);
-                    ret = mode;
-                }
-            break;
-        }
-        return ret;
+        return mEriManager.getCdmaEriIconMode(roamInd, defRoamInd);
     }
 
     /**
@@ -1130,94 +1180,6 @@
     public String getCdmaEriText() {
         int roamInd = getServiceState().getCdmaRoamingIndicator();
         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
-        String ret = "ERI text";
-
-        switch (roamInd) {
-            // Handling the standard roaming indicator (non-ERI)
-            case EriInfo.ROAMING_INDICATOR_ON:
-                ret = EriInfo.ROAMING_TEXT_0;
-            break;
-            case EriInfo.ROAMING_INDICATOR_OFF:
-                ret = EriInfo.ROAMING_TEXT_1;
-            break;
-            case EriInfo.ROAMING_INDICATOR_FLASH:
-                ret = EriInfo.ROAMING_TEXT_2;
-            break;
-
-            // Handling the standard ERI
-            case 3:
-                ret = EriInfo.ROAMING_TEXT_3;
-            break;
-            case 4:
-                ret = EriInfo.ROAMING_TEXT_4;
-            break;
-            case 5:
-                ret = EriInfo.ROAMING_TEXT_5;
-            break;
-            case 6:
-                ret = EriInfo.ROAMING_TEXT_6;
-            break;
-            case 7:
-                ret = EriInfo.ROAMING_TEXT_7;
-            break;
-            case 8:
-                ret = EriInfo.ROAMING_TEXT_8;
-            break;
-            case 9:
-                ret = EriInfo.ROAMING_TEXT_9;
-            break;
-            case 10:
-                ret = EriInfo.ROAMING_TEXT_10;
-            break;
-            case 11:
-                ret = EriInfo.ROAMING_TEXT_11;
-            break;
-            case 12:
-                ret = EriInfo.ROAMING_TEXT_12;
-            break;
-
-            // Handling the non standard Enhanced Roaming Indicator (roamInd > 63)
-            default:
-                if (!mEriManager.isEriFileLoaded()) {
-                    if(defRoamInd > 2) {
-                        Log.d(LOG_TAG, "ERI File not loaded, defRoamInd > 2, " +
-                                EriInfo.ROAMING_TEXT_2);
-                        ret = EriInfo.ROAMING_TEXT_2;
-                    } else {
-                        switch (defRoamInd) {
-                            // Handling the standard roaming indicator (non-ERI)
-                            case EriInfo.ROAMING_INDICATOR_ON:
-                                Log.d(LOG_TAG, "ERI File not loaded, " + EriInfo.ROAMING_TEXT_0);
-                                ret = EriInfo.ROAMING_TEXT_0;
-                            break;
-                            case EriInfo.ROAMING_INDICATOR_OFF:
-                                Log.d(LOG_TAG, "ERI File not loaded, " + EriInfo.ROAMING_TEXT_1);
-                                ret = EriInfo.ROAMING_TEXT_1;
-                            break;
-                            case EriInfo.ROAMING_INDICATOR_FLASH:
-                                Log.d(LOG_TAG, "ERI File not loaded, " + EriInfo.ROAMING_TEXT_2);
-                                ret = EriInfo.ROAMING_TEXT_2;
-                            break;
-                        }
-                    }
-                } else if (mEriManager.getEriInfo(roamInd) == null) {
-                    if(mEriManager.getEriInfo(defRoamInd) == null) {
-                        Log.e(LOG_TAG, "Error: defRoamInd not defined in ERI file, "
-                                + EriInfo.ROAMING_TEXT_0);
-                        ret = EriInfo.ROAMING_TEXT_0;
-                    } else {
-                        String eriText = mEriManager.getEriInfo(defRoamInd).mEriText;
-                        Log.d(LOG_TAG, "ERI entry " + roamInd + " not present, eri text: "
-                                + eriText);
-                        ret = eriText;
-                    }
-                } else {
-                    String eriText = mEriManager.getEriInfo(roamInd).mEriText;
-                    Log.d(LOG_TAG, "Using ERI text: " + eriText);
-                    ret = eriText;
-                }
-            break;
-        }
-        return ret;
+        return mEriManager.getCdmaEriText(roamInd, defRoamInd);
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
index 9af245c..fb5f0fa 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
@@ -29,21 +29,12 @@
     // Busy Tone
     static final int USER_BUSY                      = 17;
 
-    // TODO(Teleca): Should we remove commented out values?
-//    // No Tone
-//    static final int NUMBER_CHANGED               = 22;
-//    static final int STATUS_ENQUIRY               = 30;
     static final int NORMAL_UNSPECIFIED             = 31;
-//
-//    // Congestion Tone
+
+    // Congestion Tone
     static final int NO_CIRCUIT_AVAIL               = 34;
-//    static final int TEMPORARY_FAILURE            = 41;
-//    static final int SWITCHING_CONGESTION         = 42;
-//    static final int CHANNEL_NOT_AVAIL            = 44;
-//    static final int QOS_NOT_AVAIL                = 49;
-//    static final int BEARER_NOT_AVAIL             = 58;
-//
-//    // others
+
+    // others
     static final int ACM_LIMIT_EXCEEDED             = 68;
     static final int CALL_BARRED                    = 240;
     static final int FDN_BLOCKED                    = 241;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index a1d362f..c02fcd4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -24,6 +24,7 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
 import android.util.Log;
+import android.os.SystemProperties;
 
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CallTracker;
@@ -31,11 +32,12 @@
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.DriverCall;
 import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.TelephonyProperties;
 
 import java.util.ArrayList;
 import java.util.List;
 
+
 /**
  * {@hide}
  */
@@ -69,11 +71,12 @@
 
     CdmaConnection pendingMO;
     boolean hangupPendingMO;
-
+    boolean pendingCallInECM=false;
     CDMAPhone phone;
 
     boolean desiredMute = false;    // false = mute off
 
+    int pendingCallClirMode;
     Phone.State state = Phone.State.IDLE;
 
 
@@ -115,6 +118,7 @@
 
     }
 
+    @Override
     protected void finalize() {
         Log.d(LOG_TAG, "CdmaCallTracker finalized");
     }
@@ -204,7 +208,15 @@
             // Always unmute when initiating a new call
             setMute(false);
 
-            cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
+            String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+            if(inEcm.equals("false")) {
+                cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
+            } else {
+                phone.exitEmergencyCallbackMode();
+                phone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null);
+                pendingCallClirMode=clirMode;
+                pendingCallInECM=true;
+            }
         }
 
         updatePhoneState();
@@ -536,6 +548,9 @@
             droppedDuringPoll.add(pendingMO);
             pendingMO = null;
             hangupPendingMO = false;
+            if( pendingCallInECM) {
+                pendingCallInECM = false;
+            }
         }
 
         if (newRinging != null) {
@@ -847,8 +862,17 @@
                 handleRadioNotAvailable();
             break;
 
+            case EVENT_EXIT_ECM_RESPONSE_CDMA:
+               //no matter the result, we still do the same here
+               if (pendingCallInECM) {
+                   cm.dial(pendingMO.address, pendingCallClirMode, obtainCompleteMessage());
+                   pendingCallInECM = false;
+               }
+               phone.unsetOnEcbModeExitResponse(this);
+            break;
+
             default:{
-             throw new RuntimeException("unexpected event not handled");
+               throw new RuntimeException("unexpected event not handled");
             }
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaiting.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaiting.java
deleted file mode 100644
index 64841d7..0000000
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaiting.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.cdma;
-
-import com.android.internal.telephony.CdmaInformationRecord;
-
-public class CdmaCallWaiting {
-    public String number;
-    public int numberPresentation;
-    public String name;
-
-    public CdmaInformationRecord.CdmaSignalInfoRec signalInfoRecord =
-                                   new CdmaInformationRecord.CdmaSignalInfoRec();
-
-    @Override
-    public String toString() {
-        return "CdmaCallWaiting: {" + " number: " + number + " numberPresentation: "
-                + numberPresentation + " name: " + name + " signalInfoRecord: "
-                + signalInfoRecord + " }";
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
new file mode 100644
index 0000000..54dec48
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
@@ -0,0 +1,48 @@
+/*
+ * 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.telephony.cdma;
+
+/**
+ * Represents a Supplementary Service Notification received from the network.
+ *
+ * {@hide}
+ */
+public class CdmaCallWaitingNotification {
+    public String number =null;
+    public int numberPresentation = 0;
+    public String name = null;
+    public int namePresentation = 0;
+    public int isPresent = 0;
+    public int signalType = 0;
+    public int alertPitch = 0;
+    public int signal = 0;
+
+
+    public String toString()
+    {
+        return super.toString() + "Call Waiting Notification  "
+            + " number: " + number
+            + " numberPresentation: " + numberPresentation
+            + " name: " + name
+            + " namePresentation: " + namePresentation
+            + " isPresent: " + isPresent
+            + " signalType: " + signalType
+            + " alertPitch: " + alertPitch
+            + " signal: " + signal ;
+    }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 0a237c6..32442f6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -48,7 +48,7 @@
     String postDialString;      // outgoing calls only
     boolean isIncoming;
     boolean disconnected;
-
+    String cnapName;
     int index;          // index in CdmaCallTracker.connections[], -1 if unassigned
 
     /*
@@ -74,6 +74,8 @@
     DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED;
     PostDialState postDialState = PostDialState.NOT_STARTED;
     int numberPresentation = Connection.PRESENTATION_ALLOWED;
+    int cnapNamePresentation  = Connection.PRESENTATION_ALLOWED;
+
 
     Handler h;
 
@@ -86,10 +88,19 @@
     static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
 
     //***** Constants
-    static final int PAUSE_DELAY_FIRST_MILLIS = 100;
-    static final int PAUSE_DELAY_MILLIS = 3 * 1000;
     static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
-
+    static final int PAUSE_DELAY_MILLIS = 2 * 1000;
+    
+    // TODO(Moto): These should be come from a resourse file
+    // at a minimum as different carriers may want to use
+    // different characters and our general default is "," & ";".
+    // Furthermore Android supports contacts that have phone
+    // numbers entered as strings so '1-800-164flowers' would not
+    // be handled as expected. Both issues need to be resolved.
+    static final char CUSTOMERIZED_WAIT_CHAR_UPPER ='W';
+    static final char CUSTOMERIZED_WAIT_CHAR_LOWER ='w';
+    static final char CUSTOMERIZED_PAUSE_CHAR_UPPER ='P';
+    static final char CUSTOMERIZED_PAUSE_CHAR_LOWER ='p';
     //***** Inner Classes
 
     class MyHandler extends Handler {
@@ -126,6 +137,8 @@
 
         isIncoming = dc.isMT;
         createTime = System.currentTimeMillis();
+        cnapName = dc.name;
+        cnapNamePresentation = dc.namePresentation;
         numberPresentation = dc.numberPresentation;
 
         this.index = index;
@@ -134,6 +147,16 @@
         parent.attach(this, dc);
     }
 
+    CdmaConnection () {
+        owner = null;
+        h = null;
+        address = null;
+        index = -1;
+        parent = null;
+        isIncoming = true;
+        createTime = System.currentTimeMillis();
+     }
+
     /** This is an MO call, created when dialing */
     /*package*/
     CdmaConnection (Context context, String dialString, CdmaCallTracker ct, CdmaCall parent) {
@@ -144,6 +167,9 @@
         h = new MyHandler(owner.getLooper());
 
         this.dialString = dialString;
+        Log.d(LOG_TAG, "[CDMAConn] CdmaConnection: dialString=" + dialString);
+        dialString = formatDialString(dialString);
+        Log.d(LOG_TAG, "[CDMAConn] CdmaConnection:formated dialString=" + dialString);
 
         this.address = PhoneNumberUtils.extractNetworkPortion(dialString);
         this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString);
@@ -151,10 +177,15 @@
         index = -1;
 
         isIncoming = false;
+        cnapName = null;
+        cnapNamePresentation = 0;
+        numberPresentation = 0;
         createTime = System.currentTimeMillis();
 
-        this.parent = parent;
-        parent.attachFake(this, CdmaCall.State.DIALING);
+        if (parent != null) {
+            this.parent = parent;
+            parent.attachFake(this, CdmaCall.State.DIALING);
+        }
     }
 
     public void dispose() {
@@ -186,10 +217,22 @@
         return (isIncoming ? "incoming" : "outgoing");
     }
 
+    public String getOrigDialString(){
+        return dialString;
+    }
+
     public String getAddress() {
         return address;
     }
 
+    public String getCnapName() {
+        return cnapName;
+    }
+
+    public int getCnapNamePresentation() {
+        return cnapNamePresentation;
+    }
+
     public CdmaCall getCall() {
         return parent;
     }
@@ -320,6 +363,16 @@
         }
     }
 
+    /**
+     * Used for 3way call only
+     */
+    void update (CdmaConnection c) {
+        address = c.address;
+        cnapName = c.cnapName;
+        cnapNamePresentation = c.cnapNamePresentation;
+        numberPresentation = c.numberPresentation;
+    }
+
     public void cancelPostDial() {
         setPostDialState(PostDialState.CANCELLED);
     }
@@ -355,7 +408,7 @@
             case CallFailCause.CDMA_LOCKED_UNTIL_POWER_CYCLE:
                 return DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE;
             case CallFailCause.CDMA_DROP:
-                return DisconnectCause.CDMA_DROP;
+                return DisconnectCause.LOST_SIGNAL; // TODO(Moto): wink/dave changed from CDMA_DROP;
             case CallFailCause.CDMA_INTERCEPT:
                 return DisconnectCause.CDMA_INTERCEPT;
             case CallFailCause.CDMA_REORDER:
@@ -434,6 +487,20 @@
             changed = true;
         }
 
+        // A null cnapName should be the same as ""
+        if (null != dc.name) {
+            if (cnapName != dc.name) {
+                cnapName = dc.name;
+                changed = true;
+            }
+        } else {
+            cnapName = "";
+            // TODO(Moto): Should changed = true if cnapName wasn't previously ""
+        }
+        log("--dssds----"+cnapName);
+        cnapNamePresentation = dc.namePresentation;
+        numberPresentation = dc.numberPresentation;
+
         if (newParent != parent) {
             if (parent != null) {
                 parent.detach(this);
@@ -533,25 +600,13 @@
         if (PhoneNumberUtils.is12Key(c)) {
             owner.cm.sendDtmf(c, h.obtainMessage(EVENT_DTMF_DONE));
         } else if (c == PhoneNumberUtils.PAUSE) {
-            // From TS 22.101:
+            setPostDialState(PostDialState.PAUSE);
 
-            // "The first occurrence of the "DTMF Control Digits Separator"
-            //  shall be used by the ME to distinguish between the addressing
-            //  digits (i.e. the phone number) and the DTMF digits...."
-
-            if (nextPostDialChar == 1) {
-                // The first occurrence.
-                // We don't need to pause here, but wait for just a bit anyway
-                h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE),
-                                            PAUSE_DELAY_FIRST_MILLIS);
-            } else {
-                // It continues...
-                // "Upon subsequent occurrences of the separator, the UE shall
-                //  pause again for 3 seconds (\u00B1 20 %) before sending any
-                //  further DTMF digits."
-                h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE),
+            // Upon occurrences of the separator, the UE shall
+            // pause again for 2 seconds before sending any
+            // further DTMF digits.
+            h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE),
                                             PAUSE_DELAY_MILLIS);
-            }
         } else if (c == PhoneNumberUtils.WAIT) {
             setPostDialState(PostDialState.WAIT);
         } else if (c == PhoneNumberUtils.WILD) {
@@ -563,17 +618,40 @@
         return true;
     }
 
-    public String
-    getRemainingPostDialString() {
+    public String getRemainingPostDialString() {
         if (postDialState == PostDialState.CANCELLED
-            || postDialState == PostDialState.COMPLETE
-            || postDialString == null
-            || postDialString.length() <= nextPostDialChar
-        ) {
+                || postDialState == PostDialState.COMPLETE
+                || postDialString == null
+                || postDialString.length() <= nextPostDialChar) {
             return "";
         }
 
-        return postDialString.substring(nextPostDialChar);
+        String subStr = postDialString.substring(nextPostDialChar);
+        if (subStr != null) {
+            int wIndex = subStr.indexOf(PhoneNumberUtils.WAIT);
+            int pIndex = subStr.indexOf(PhoneNumberUtils.PAUSE);
+
+            // TODO(Moto): Courtesy of jsh; is this simpler expression equivalent?
+            //
+            //    if (wIndex > 0 && (wIndex < pIndex || pIndex <= 0)) {
+            //        subStr = subStr.substring(0, wIndex);
+            //    } else if (pIndex > 0) {
+            //        subStr = subStr.substring(0, pIndex);
+            //    }
+            
+            if (wIndex > 0 && pIndex > 0) {
+                if (wIndex > pIndex) {
+                    subStr = subStr.substring(0, pIndex);
+                } else {
+                    subStr = subStr.substring(0, wIndex);
+                }
+            } else if (wIndex > 0) {
+                subStr = subStr.substring(0, wIndex);
+            } else if (pIndex > 0) {
+                subStr = subStr.substring(0, pIndex);
+            }
+        }
+        return subStr;
     }
 
     @Override
@@ -591,8 +669,7 @@
         releaseWakeLock();
     }
 
-    private void
-    processNextPostDialChar() {
+    void processNextPostDialChar() {
         char c = 0;
         Registrant postDialHandler;
 
@@ -698,21 +775,18 @@
         postDialState = s;
     }
 
-    private void
-    createWakeLock(Context context) {
-        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+    private void createWakeLock(Context context) {
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
     }
 
-    private void
-    acquireWakeLock() {
+    private void acquireWakeLock() {
         log("acquireWakeLock");
         mPartialWakeLock.acquire();
     }
 
-    private void
-    releaseWakeLock() {
-        synchronized(mPartialWakeLock) {
+    private void releaseWakeLock() {
+        synchronized (mPartialWakeLock) {
             if (mPartialWakeLock.isHeld()) {
                 log("releaseWakeLock");
                 mPartialWakeLock.release();
@@ -720,6 +794,119 @@
         }
     }
 
+    private static boolean isPause(char c) {
+        if (c == CUSTOMERIZED_PAUSE_CHAR_UPPER || c == CUSTOMERIZED_PAUSE_CHAR_LOWER
+                || c == PhoneNumberUtils.PAUSE) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private static boolean isWait(char c) {
+        if (c == CUSTOMERIZED_WAIT_CHAR_LOWER || c == CUSTOMERIZED_WAIT_CHAR_UPPER
+                || c == PhoneNumberUtils.WAIT) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * format string
+     * convert "+" to "011"
+     * handle corner cases for PAUSE/WAIT
+     * If PAUSE/WAIT sequence at the end,ignore them
+     * If PAUSE/WAIT sequence in the middle, then if there is any WAIT
+     * in PAUSE/WAIT sequence, treat them like WAIT
+     * If PAUSE followed by WAIT or WAIT followed by PAUSE in the middle,
+     * treat them like just  PAUSE or WAIT
+     */
+    private static String formatDialString(String phoneNumber) {
+        if (phoneNumber == null) {
+            return null;
+        }
+        int length = phoneNumber.length();
+        StringBuilder ret = new StringBuilder();
+
+        // TODO(Moto): Modifying the for loop index is confusing, a
+        // while loop is probably better and overall this code is
+        // hard to follow. If this was routine was refactored and
+        // used several private methods with good names to make it
+        // easier to follow.
+        for (int i = 0; i < length; i++) {
+            char c = phoneNumber.charAt(i);
+
+            if (PhoneNumberUtils.isDialable(c)) {
+                if (c == '+') {
+                    // TODO(Moto): Is this valid for "all" countries????
+                    // should probably be pulled from a resource based
+                    // on current contry code (MCC).
+                    ret.append("011");
+                } else {
+                    ret.append(c);
+                }
+            } else if (isPause(c) || isWait(c)) {
+                if (i < length - 1) { // if PAUSE/WAIT not at the end
+                    int index = 0;
+                    boolean wMatched = false;
+                    for (index = i + 1; index < length; index++) {
+                        char cNext = phoneNumber.charAt(index);
+                        // if there is any W inside P/W sequence,mark it
+                        if (isWait(cNext)) {
+                            wMatched = true;
+                        }
+                        // if any characters other than P/W chars after P/W sequence
+                        // we break out the loop and append the correct
+                        if (!isWait(cNext) && !isPause(cNext)) {
+                            break;
+                        }
+                    }
+                    if (index == length) {
+                        // it means there is no dialable character after PAUSE/WAIT
+                        i = length - 1;
+                        break;
+                    } else {// means index <length
+                        if (isPause(c)) {
+                            c = PhoneNumberUtils.PAUSE;
+                        } else if (isWait(c)) {
+                            c = PhoneNumberUtils.WAIT;
+                        }
+
+                        if (index == i + 1) {
+                            ret.append(c);
+                        } else if (isWait(c)) {
+                            // for case like 123WP456 =123P456
+                            if ((index == i + 2) && isPause(phoneNumber.charAt(index - 1))) {
+                                // skip W,append P
+                                ret.append(PhoneNumberUtils.PAUSE);
+                            } else {
+                                // append W
+                                ret.append(c);
+                            }
+                            i = index - 1;
+                        } else if (isPause(c)) {
+
+                            // for case like 123PW456 =123W456, skip p, append W
+                            // or there is 1 W in between, treat the whole PW
+                            // sequence as W
+                            if (wMatched == true) {
+                                // skip P,append W
+                                ret.append(PhoneNumberUtils.WAIT);
+                                i = index - 1;
+                            } else {
+                                ret.append(c);
+                            }
+                        } // end of pause case
+                    } // end of index <length, it means dialable characters after P/W
+                }
+            } else { // if it's characters other than P/W
+                ret.append(c);
+            }
+        }
+        return ret.toString();
+    }
+
     private void log(String msg) {
         Log.d(LOG_TAG, "[CDMAConn] " + msg);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index bf58ab7..b92e9e4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -361,9 +361,7 @@
         boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
 
         if ((state == State.IDLE || state == State.SCANNING)
-                && (psState == ServiceState.RADIO_TECHNOLOGY_1xRTT ||
-                    psState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 ||
-                    psState == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
+                && (psState == ServiceState.STATE_IN_SERVICE)
                 && ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) ||
                         mCdmaPhone.mRuimRecords.getRecordsLoaded())
                 && (mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
@@ -675,7 +673,7 @@
         if (state == State.FAILED) {
             cleanUpConnection(false, null);
         }
-        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onNVReady() {
@@ -688,8 +686,8 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
-    protected void onTrySetupData() {
-        trySetupData(null);
+    protected void onTrySetupData(String reason) {
+        trySetupData(reason);
     }
 
     /**
@@ -769,7 +767,10 @@
             }
 
             if (tryAgain(cause)) {
-                    trySetupData(reason);
+                // Wait a bit before trying again, so that
+                // we're not tying up the RIL command channel
+                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
+                        RECONNECT_DELAY_INITIAL_MILLIS);
             } else {
                 startDelayedRetry(cause, reason);
             }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java
new file mode 100644
index 0000000..93a6aa4
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java
@@ -0,0 +1,75 @@
+/*
+ * 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.telephony.cdma;
+import static com.android.internal.telephony.RILConstants.*;
+
+public final class CdmaInformationRecords {
+    public static final int RIL_CDMA_DISPLAY_INFO_REC = 0;
+    public static final int RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC = 1;
+    public static final int RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC = 2;
+    public static final int RIL_CDMA_CONNECTED_NUMBER_INFO_REC = 3;
+    public static final int RIL_CDMA_SIGNAL_INFO_REC = 4;
+    public static final int RIL_CDMA_REDIRECTING_NUMBER_INFO_REC = 5;
+    public static final int RIL_CDMA_LINE_CONTROL_INFO_REC = 6;
+    public static final int RIL_CDMA_EXTENDED_DISPLAY_INFO_REC = 7;
+    public static final int RIL_CDMA_T53_CLIR_INFO_REC = 8;
+    public static final int RIL_CDMA_T53_RELEASE_INFO_REC = 9;
+    public static final int RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC = 10;
+
+    public boolean isDispInfo;
+    public boolean isSignInfo;
+    public String cdmaDisplayInfoRecord;
+    public int[] cdmaSignalInfoRecord;
+
+    private static final int ALPHA_LEN_FOR_DISPLAY_INFO = 64;
+
+    public CdmaInformationRecords() {
+        isDispInfo = false;
+        isSignInfo = false;
+    }
+
+    public void setDispInfo(String resString) {
+          isDispInfo = true;
+          cdmaDisplayInfoRecord = resString;
+    }
+
+    public void setSignInfo(int isPresent, int signalType, int alertPitch, int signal) {
+        isSignInfo = true;
+        cdmaSignalInfoRecord = new int[4];
+        cdmaSignalInfoRecord[0] = isPresent;
+        cdmaSignalInfoRecord[1] = signalType;
+        cdmaSignalInfoRecord[2] = alertPitch;
+        cdmaSignalInfoRecord[3] = signal;
+    }
+
+    public String recordToString (int record) {
+        switch(record) {
+        case RIL_CDMA_DISPLAY_INFO_REC: return "RIL_CDMA_DISPLAY_INFO_REC";
+        case RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC: return "RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC";
+        case RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC: return "RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC";
+        case RIL_CDMA_CONNECTED_NUMBER_INFO_REC: return "RIL_CDMA_CONNECTED_NUMBER_INFO_REC";
+        case RIL_CDMA_SIGNAL_INFO_REC: return "RIL_CDMA_SIGNAL_INFO_REC";
+        case RIL_CDMA_REDIRECTING_NUMBER_INFO_REC: return "RIL_CDMA_REDIRECTING_NUMBER_INFO_REC";
+        case RIL_CDMA_LINE_CONTROL_INFO_REC: return "RIL_CDMA_LINE_CONTROL_INFO_REC";
+        case RIL_CDMA_EXTENDED_DISPLAY_INFO_REC: return "RIL_CDMA_EXTENDED_DISPLAY_INFO_REC";
+        case RIL_CDMA_T53_CLIR_INFO_REC: return "RIL_CDMA_T53_CLIR_INFO_REC";
+        case RIL_CDMA_T53_RELEASE_INFO_REC: return "RIL_CDMA_T53_RELEASE_INFO_REC";
+        case RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC: return "RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC";
+        default: return "<unknown record>";
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index a3d00d7..f12e7e3 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -17,15 +17,18 @@
 package com.android.internal.telephony.cdma;
 
 
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.os.AsyncResult;
 import android.os.Message;
+import android.provider.Telephony.Sms.Intents;
 import android.util.Config;
 import android.util.Log;
 
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SMSDispatcher;
@@ -330,10 +333,10 @@
     }
 
     /** {@inheritDoc} */
-    protected void acknowledgeLastIncomingSms(boolean success, Message response){
+    protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
         // FIXME unit test leaves cm == null. this should change
         if (mCm != null) {
-            mCm.acknowledgeLastIncomingCdmaSms(success, response);
+            mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response);
         }
     }
 
@@ -352,4 +355,17 @@
         mCm.setCdmaBroadcastConfig(configValuesArray, response);
     }
 
+    private int resultToCause(int rc) {
+        switch (rc) {
+            case Activity.RESULT_OK:
+            case Intents.RESULT_SMS_HANDLED:
+                // Cause code is ignored on success.
+                return 0;
+            case Intents.RESULT_SMS_OUT_OF_MEMORY:
+                return CommandsInterface.CDMA_SMS_FAIL_CAUSE_RESOURCE_SHORTAGE;
+            case Intents.RESULT_SMS_GENERIC_ERROR:
+            default:
+                return CommandsInterface.CDMA_SMS_FAIL_CAUSE_OTHER_TERMINAL_PROBLEM;
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index dbb0f93..a9c810d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -24,6 +24,7 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.SystemClock;
@@ -38,7 +39,9 @@
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Config;
 import android.util.TimeUtils;
+import java.util.Calendar;
 
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
@@ -66,64 +69,66 @@
  * {@hide}
  */
 final class CdmaServiceStateTracker extends ServiceStateTracker {
+
     //***** Instance Variables
     CDMAPhone phone;
     CdmaCellLocation cellLoc;
     CdmaCellLocation newCellLoc;
 
     /**
-     * TODO(Teleca): I don't think the initialization to -1 for all of these are
-     * really necessary, I don't seem them in GsmServiceStateTracker. Also,
-     * all of the other initialization is unnecessary as I believe Java guarantees
-     * 0, false & null, but if you think it's better than do all of them there are
-     * a few that aren't initialized.
-     */
-
-    /**
      *  The access technology currently in use: DATA_ACCESS_
      */
     private int networkType = 0;
     private int newNetworkType = 0;
 
     private boolean mCdmaRoaming = false;
-    private int mRoamingIndicator = -1;
-    private int mIsInPrl = -1;
-    private int mDefaultRoamingIndicator = -1;
+    private int mRoamingIndicator;
+    private boolean mIsInPrl;
+    private int mDefaultRoamingIndicator;
 
-    /**
-     * TODO(Teleca): Maybe these should be initialized to STATE_OUT_OF_SERVICE like gprsState
-     * in GsmServiceStateTracker and remove the comment.
-     */
-    private int cdmaDataConnectionState = -1; // Initially we assume no data connection
-    private int newCdmaDataConnectionState = -1; // Initially we assume no data connection
+    // Initially we assume no data connection
+    private int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+    private int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
     private int mRegistrationState = -1;
     private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
     private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
 
+    // Sometimes we get the NITZ time before we know what country we are in.
+    // Keep the time zone information from the NITZ string so we can fix
+    // the time zone once know the country.
+    private boolean mNeedFixZone = false;
+    private int mZoneOffset;
+    private boolean mZoneDst;
+    private long mZoneTime;
     private boolean mGotCountryCode = false;
+    String mSavedTimeZone;
+    long mSavedTime;
+    long mSavedAtTime;
 
     // We can't register for SIM_RECORDS_LOADED immediately because the
     // SIMRecords object may not be instantiated yet.
-    private boolean mNeedToRegForRuimLoaded;
+    private boolean mNeedToRegForRuimLoaded = false;
+
+    // Wake lock used while setting time of day.
+    private PowerManager.WakeLock mWakeLock;
+    private static final String WAKELOCK_TAG = "ServiceStateTracker";
 
     // Keep track of SPN display rules, so we only broadcast intent if something changes.
     private String curSpn = null;
-    private String curEriText = null;
+    private String curPlmn = null; // it contains the name of the registered network in CDMA can
+                                   // be the ONS or ERI text
     private int curSpnRule = 0;
 
-    private String mMdn = null;
-    private int mHomeSystemId = -1;
-    private int mHomeNetworkId = -1;
-    private String mMin = null;
+    private String mMdn;
+    private int mHomeSystemId;
+    private int mHomeNetworkId;
+    private String mMin;
+
     private boolean isEriTextLoaded = false;
     private boolean isSubscriptionFromRuim = false;
 
-    /**
-     * TODO(Teleca): Is this purely for debugging purposes, or do we expect this string to be
-     * passed around (eg, to the UI)? If the latter, it would be better to pass around a
-     * reasonCode, and let the UI provide its own strings.
-     */
-    private String mRegistrationDeniedReason = null;
+    // Registration Denied Reason, General/Authentication Failure, used only for debugging purposes
+    private String mRegistrationDeniedReason;
 
     //***** Constants
     static final String LOG_TAG = "CDMA";
@@ -134,7 +139,8 @@
         @Override
         public void onChange(boolean selfChange) {
             Log.i("CdmaServiceStateTracker", "Auto time state called ...");
-            //NOTE in CDMA NITZ is not used
+            revertToNitz();
+
         }
     };
 
@@ -152,10 +158,15 @@
         newCellLoc = new CdmaCellLocation();
         mSignalStrength = new SignalStrength();
 
+        PowerManager powerManager =
+                (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
         cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
         cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
 
         cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null);
+        cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
         cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
 
         cm.registerForRUIMReady(this, EVENT_RUIM_READY, null);
@@ -188,6 +199,7 @@
         phone.unregisterForEriFileLoaded(this);
         phone.mRuimRecords.unregisterForRecordsLoaded(this);
         cm.unSetOnSignalStrengthUpdate(this);
+        cm.unSetOnNITZTime(this);
         cr.unregisterContentObserver(this.mAutoTimeObserver);
     }
 
@@ -219,9 +231,7 @@
         Registrant r = new Registrant(h, what, obj);
         cdmaDataConnectionAttachedRegistrants.add(r);
 
-        if (cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT
-           || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0
-           || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) {
+        if (cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE) {
             r.notifyRegistrant();
         }
     }
@@ -240,9 +250,7 @@
         Registrant r = new Registrant(h, what, obj);
         cdmaDataConnectionDetachedRegistrants.add(r);
 
-        if (cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT
-           && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0
-           && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) {
+        if (cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE) {
             r.notifyRegistrant();
         }
     }
@@ -378,6 +386,15 @@
             cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
             break;
 
+        case EVENT_NITZ_TIME:
+            ar = (AsyncResult) msg.obj;
+
+            String nitzString = (String)((Object[])ar.result)[0];
+            long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
+
+            setTimeFromNITZString(nitzString, nitzReceiveTime);
+            break;
+
         case EVENT_SIGNAL_STRENGTH_UPDATE:
             // This is a notification from
             // CommandsInterface.setOnSignalStrengthUpdate
@@ -451,30 +468,40 @@
     }
 
     protected void updateSpnDisplay() {
+        String spn = "";
+        boolean showSpn = false;
+        String plmn = "";
+        boolean showPlmn = false;
+        int rule = 0;
+        if (cm.getRadioState().isRUIMReady()) {
+            // TODO RUIM SPN is not implemnted, EF_SPN has to be read and Display Condition
+            //   Character Encoding, Language Indicator and SPN has to be set
+            // rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric());
+            // spn = phone.mSIMRecords.getServiceProvideName();
+            plmn = ss.getOperatorAlphaLong(); // mOperatorAlphaLong contains the ONS
+            // showSpn = (rule & ...
+            showPlmn = true; // showPlmn = (rule & ...
 
-        // TODO(Teleca): Check this method again, because it is not sure at the moment how
-        // the RUIM handles the SIM stuff. Please complete this function.
+        } else {
+            // In this case there is no SPN available from RUIM, we show the ERI text
+            plmn = ss.getOperatorAlphaLong(); // mOperatorAlphaLong contains the ERI text
+            showPlmn = true;
+        }
 
-        //int rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric());
-        String spn = null; //phone.mRuimRecords.getServiceProviderName();
-        String eri = ss.getOperatorAlphaLong();
-
-        if (!TextUtils.equals(this.curEriText, eri)) {
-            //TODO  (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN;
-            boolean showSpn = false;
-            //TODO  (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN;
-            boolean showEri = true;
+        if (rule != curSpnRule
+                || !TextUtils.equals(spn, curSpn)
+                || !TextUtils.equals(plmn, curPlmn)) {
             Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
             intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
             intent.putExtra(Intents.EXTRA_SPN, spn);
-            intent.putExtra(Intents.EXTRA_SHOW_PLMN, showEri);
-            intent.putExtra(Intents.EXTRA_PLMN, eri);
+            intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
+            intent.putExtra(Intents.EXTRA_PLMN, plmn);
             phone.getContext().sendStickyBroadcast(intent);
         }
 
-        //curSpnRule = rule;
-        //curSpn = spn;
-        this.curEriText = eri;
+        curSpnRule = rule;
+        curSpn = spn;
+        curPlmn = plmn;
     }
 
     /**
@@ -516,54 +543,39 @@
             }
         } else try {
             switch (what) {
-            case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE,
-                                                     // the offset is because we don't want the
-                                                     // first 3 values in the
-                                                     // responseValuesRegistrationState array.
-                final int offset = 3;
+            case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE.
                 states = (String[])ar.result;
 
-                /**
-                 * TODO(Teleca): Change from array to a "Class" or local
-                 * variables so names instead of index's can be used.
-                 */
-                int responseValuesRegistrationState[] = {
-                        -1, //[0] radioTechnology
-                        -1, //[1] baseStationId
-                        -1, //[2] baseStationLatitude
-                        -1, //[3] baseStationLongitude
-                         0, //[4] cssIndicator; init with 0, because it is treated as a boolean
-                        -1, //[5] systemId
-                        -1, //[6] networkId
-                        -1, //[7] Roaming indicator
-                        -1, //[8] Indicates if current system is in PRL
-                        -1, //[9] Is default roaming indicator from PRL
-                        -1, //[10] If registration state is 3 this is reason for denial
-                };
+                int registrationState = 4;     //[0] registrationState
+                int radioTechnology = -1;      //[3] radioTechnology
+                int baseStationId = -1;        //[4] baseStationId
+                int baseStationLatitude = -1;  //[5] baseStationLatitude
+                int baseStationLongitude = -1; //[6] baseStationLongitude
+                int cssIndicator = 0;          //[7] init with 0, because it is treated as a boolean
+                int systemId = 0;              //[8] systemId
+                int networkId = 0;             //[9] networkId
+                int roamingIndicator = -1;     //[10] Roaming indicator
+                int systemIsInPrl = 0;         //[11] Indicates if current system is in PRL
+                int defaultRoamingIndicator = 0;  //[12] Is default roaming indicator from PRL
+                int reasonForDenial = 0;       //[13] Denial reason if registrationState = 3
 
                 if (states.length == 14) {
                     try {
-                        this.mRegistrationState = Integer.parseInt(states[0]);
-                    } catch (NumberFormatException ex) {
-                        Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
-                    }
-                    try {
-                        responseValuesRegistrationState[0] = Integer.parseInt(states[3]);
-                        responseValuesRegistrationState[1] = Integer.parseInt(states[4], 16);
-                        responseValuesRegistrationState[2] = Integer.parseInt(states[5], 16);
-                        responseValuesRegistrationState[3] = Integer.parseInt(states[6], 16);
-                        responseValuesRegistrationState[4] = Integer.parseInt(states[7]);
-                        responseValuesRegistrationState[5] = Integer.parseInt(states[8]);
-                        responseValuesRegistrationState[6] = Integer.parseInt(states[9]);
-                        responseValuesRegistrationState[7] = Integer.parseInt(states[10]);
-                        responseValuesRegistrationState[8] = Integer.parseInt(states[11]);
-                        responseValuesRegistrationState[9] = Integer.parseInt(states[12]);
-                        responseValuesRegistrationState[10] = Integer.parseInt(states[13]);
+                        registrationState = Integer.parseInt(states[0]);
+                        radioTechnology = Integer.parseInt(states[3]);
+                        baseStationId = Integer.parseInt(states[4], 16);
+                        baseStationLatitude = Integer.parseInt(states[5], 16);
+                        baseStationLongitude = Integer.parseInt(states[6], 16);
+                        cssIndicator = Integer.parseInt(states[7]);
+                        systemId = Integer.parseInt(states[8]);
+                        networkId = Integer.parseInt(states[9]);
+                        roamingIndicator = Integer.parseInt(states[10]);
+                        systemIsInPrl = Integer.parseInt(states[11]);
+                        defaultRoamingIndicator = Integer.parseInt(states[12]);
+                        reasonForDenial = Integer.parseInt(states[13]);
                     }
                     catch(NumberFormatException ex) {
-                        Log.w(LOG_TAG, "Warning! There is an unexpected value"
-                            + "returned as response from "
-                            + "RIL_REQUEST_REGISTRATION_STATE.");
+                        Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
                     }
                 } else {
                     throw new RuntimeException("Warning! Wrong number of parameters returned from "
@@ -571,29 +583,28 @@
                                          + states.length);
                 }
 
-                mCdmaRoaming = regCodeIsRoaming(this.mRegistrationState);
-                this.newCdmaDataConnectionState =
-                    radioTechnologyToServiceState(responseValuesRegistrationState[0]);
-                newSS.setState (regCodeToServiceState(this.mRegistrationState));
-                newSS.setRadioTechnology(responseValuesRegistrationState[0]);
-                newSS.setCssIndicator(responseValuesRegistrationState[4]);
-                newSS.setSystemAndNetworkId(responseValuesRegistrationState[5],
-                    responseValuesRegistrationState[6]);
+                mRegistrationState = registrationState;
+                mCdmaRoaming = regCodeIsRoaming(registrationState);
+                newSS.setState (regCodeToServiceState(registrationState));
 
-                mRoamingIndicator = responseValuesRegistrationState[7];
-                mIsInPrl = responseValuesRegistrationState[8];
-                mDefaultRoamingIndicator = responseValuesRegistrationState[9];
+                this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology);
+                newSS.setRadioTechnology(radioTechnology);
+                newNetworkType = radioTechnology;
 
-                newNetworkType = responseValuesRegistrationState[0];
+                newSS.setCssIndicator(cssIndicator);
+                newSS.setSystemAndNetworkId(systemId, networkId);
+                mRoamingIndicator = roamingIndicator;
+                mIsInPrl = (systemIsInPrl == 0) ? false : true;
+                mDefaultRoamingIndicator = defaultRoamingIndicator;
+
 
                 // values are -1 if not available
-                newCellLoc.setCellLocationData(responseValuesRegistrationState[1],
-                                               responseValuesRegistrationState[2],
-                                               responseValuesRegistrationState[3]);
+                newCellLoc.setCellLocationData(baseStationId, baseStationLatitude,
+                        baseStationLongitude);
 
-                if (responseValuesRegistrationState[10] == 0) {
+                if (reasonForDenial == 0) {
                     mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN;
-                } else if (responseValuesRegistrationState[10] == 1) {
+                } else if (reasonForDenial == 1) {
                     mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH;
                 } else {
                     mRegistrationDeniedReason = "";
@@ -608,9 +619,7 @@
                 String opNames[] = (String[])ar.result;
 
                 if (opNames != null && opNames.length >= 3) {
-                    // TODO(Teleca): Is this necessary here and in the else clause?
-                    newSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
-                    if (phone.mCM.getRadioState().isNVReady()) {
+                    if (cm.getRadioState().isNVReady()) {
                         // In CDMA in case on NV the ss.mOperatorAlphaLong is set later with the
                         // ERI text, so here is ignored what is coming from the modem
                         newSS.setOperatorName(null, opNames[1], opNames[2]);
@@ -662,28 +671,25 @@
                 newSS.setRoaming(mCdmaRoaming);
             }
 
-            /**
-             * TODO(Teleca): This would be simpler if mIsInPrl was a "boolean" as the
-             * name implies rather than tri-state. Above I've suggested that the -1's
-             * might be able to be removed, if so please simplify this. Otherwise change
-             * the name to mPrlState or some such. Also the logic can be simplified
-             * by testing for "mIsInPrl" only once.
-             */
             // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
-            // TODO(Teleca): use constants for the standard roaming indicators
-            if (mIsInPrl == 0 && mRegistrationState == 5) {
-                // System is acquired but prl not loaded or no prl match
-                newSS.setCdmaRoamingIndicator(2); //FLASHING
-            } else if (!namMatch && (mIsInPrl == 1)) {
-                // System is acquired, no nam match, prl match
-                newSS.setCdmaRoamingIndicator(mRoamingIndicator);
-            } else if (namMatch && (mIsInPrl == 1) && mRoamingIndicator <= 2) {
-                // System is acquired, nam match, prl match, mRoamingIndicator <= 2
-                newSS.setCdmaRoamingIndicator(1); //OFF
-            } else if (namMatch && (mIsInPrl == 1) && mRoamingIndicator > 2) {
-                // System is acquired, nam match, prl match, mRoamingIndicator > 2
-                newSS.setCdmaRoamingIndicator(mRoamingIndicator);
-            }
+            // TODO(Teleca): Validate this is correct.
+            if (mIsInPrl) {
+                if (namMatch && (mRoamingIndicator <= 2)) {
+                        // System is acquired, prl match, nam match and mRoamingIndicator <= 2
+                        newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
+                } else {
+                    // System is acquired, prl match, no nam match  or mRoamingIndicator > 2
+                    newSS.setCdmaRoamingIndicator(mRoamingIndicator);                    
+                }
+            } else {
+                if (mRegistrationState == 5) {
+                    // System is acquired but prl not loaded or no prl match
+                    newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+                } else {
+                    // Use the default indicator
+                }
+            }            
+            
             newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
 
             // NOTE: Some operator may require to override the mCdmaRoaming (set by the modem)
@@ -692,7 +698,7 @@
             if (DBG) {
                 log("Set CDMA Roaming Indicator to: " + newSS.getCdmaRoamingIndicator()
                     + ". mCdmaRoaming = " + mCdmaRoaming + ",  namMatch = " + namMatch
-                    + ", mIsInPrl= " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator
+                    + ", mIsInPrl = " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator
                     + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
             }
             pollStateDone();
@@ -800,8 +806,44 @@
         return ret;
     }
 
-    private void
-    pollStateDone() {
+    private void fixTimeZone(String isoCountryCode) {
+        TimeZone zone = null;
+        // If the offset is (0, false) and the time zone property
+        // is set, use the time zone property rather than GMT.
+        String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
+        if ((mZoneOffset == 0) && (mZoneDst == false) && (zoneName != null)
+                && (zoneName.length() > 0)
+                && (Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode) < 0)) {
+            // For NITZ string without time zone,
+            // need adjust time to reflect default time zone setting
+            zone = TimeZone.getDefault();
+            long tzOffset;
+            tzOffset = zone.getOffset(System.currentTimeMillis());
+            if (getAutoTime()) {
+                setAndBroadcastNetworkSetTime(System.currentTimeMillis() - tzOffset);
+            } else {
+                // Adjust the saved NITZ time to account for tzOffset.
+                mSavedTime = mSavedTime - tzOffset;
+            }
+        } else if (isoCountryCode.equals("")) {
+            // Country code not found. This is likely a test network.
+            // Get a TimeZone based only on the NITZ parameters (best guess).
+            zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
+        } else {
+            zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, isoCountryCode);
+        }
+
+        mNeedFixZone = false;
+
+        if (zone != null) {
+            if (getAutoTime()) {
+                setAndBroadcastNetworkSetTimeZone(zone.getID());
+            }
+            saveNitzTimeZone(zone.getID());
+        }
+    }
+
+    private void pollStateDone() {
         if (DBG) log("Poll ServiceState done: oldSS=[" + ss + "] newSS=[" + newSS + "]");
 
         boolean hasRegistered =
@@ -813,20 +855,12 @@
             && newSS.getState() != ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionAttached =
-            (this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT
-                    && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0
-                    && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A)
-                    && (this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT
-                    || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0
-                    || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A);
+            this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE
+            && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionDetached =
-            (this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT
-                    || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0
-                    || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
-                    && (this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT
-                    && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0
-                    && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A);
+            this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE
+            && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionChanged =
                        cdmaDataConnectionState != newCdmaDataConnectionState;
@@ -869,18 +903,16 @@
         }
 
         if (hasChanged) {
-            if (phone.mCM.getRadioState().isNVReady()) {
+            if (cm.getRadioState().isNVReady()) {
                 String eriText;
                 // Now the CDMAPhone sees the new ServiceState so it can get the new ERI text
                 if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
                     eriText = phone.getCdmaEriText();
                 } else {
-                    // Note that this is valid only for mRegistrationState 2,3,4, not 0!
-                    /**
-                     * TODO(Teleca): From the comment this apparently isn't always true
-                     * should there be additional logic with other strings?
-                     */
-                    eriText = EriInfo.SEARCHING_TEXT;
+                    // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for
+                    // mRegistrationState 0,2,3 and 4
+                    eriText = phone.getContext().getText(
+                            com.android.internal.R.string.roamingTextSearching).toString();
                 }
                 ss.setCdmaEriText(eriText);
             }
@@ -896,9 +928,9 @@
             if (operatorNumeric == null) {
                 phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, "");
             } else {
-                String iso = "";
+                String isoCountryCode = "";
                 try{
-                    iso = MccTable.countryCodeForMcc(Integer.parseInt(
+                    isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(
                             operatorNumeric.substring(0,3)));
                 } catch ( NumberFormatException ex){
                     Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
@@ -906,8 +938,11 @@
                     Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
                 }
 
-                phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso);
+                phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, isoCountryCode);
                 mGotCountryCode = true;
+                if (mNeedFixZone) {
+                    fixTimeZone(isoCountryCode);
+                }
             }
 
             phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING,
@@ -975,6 +1010,12 @@
         return guess;
     }
 
+    /**
+     * TODO: This code is exactly the same as in GsmServiceStateTracker
+     * and has a TODO to not poll signal strength if screen is off.
+     * This code should probably be hoisted to the base class so
+     * the fix, when added, works for both.
+     */
     private void
     queueNextSignalStrengthPoll() {
         if (dontPollSignalStrength || (cm.getRadioState().isGsm())) {
@@ -988,7 +1029,7 @@
         msg = obtainMessage();
         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
 
-        // TODO(Teleca): Don't poll signal strength if screen is off
+        // TODO Don't poll signal strength if screen is off
         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
     }
 
@@ -1036,8 +1077,8 @@
     }
 
 
-    private int radioTechnologyToServiceState(int code) {
-        int retVal = ServiceState.RADIO_TECHNOLOGY_UNKNOWN;
+    private int radioTechnologyToDataServiceState(int code) {
+        int retVal = ServiceState.STATE_OUT_OF_SERVICE;
         switch(code) {
         case 0:
         case 1:
@@ -1046,14 +1087,10 @@
         case 4:
         case 5:
             break;
-        case 6:
-            retVal = ServiceState.RADIO_TECHNOLOGY_1xRTT;
-            break;
-        case 7:
-            retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_0;
-            break;
-        case 8:
-            retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_A;
+        case 6: // RADIO_TECHNOLOGY_1xRTT
+        case 7: // RADIO_TECHNOLOGY_EVDO_0
+        case 8: // RADIO_TECHNOLOGY_EVDO_A
+            retVal = ServiceState.STATE_IN_SERVICE;
             break;
         default:
             Log.e(LOG_TAG, "Wrong radioTechnology code.");
@@ -1123,6 +1160,169 @@
         return cdmaRoaming && !(equalsOnsl || equalsOnss);
     }
 
+
+    /**
+     * nitzReceiveTime is time_t that the NITZ time was posted
+     */
+
+    private
+    void setTimeFromNITZString (String nitz, long nitzReceiveTime)
+    {
+        // "yy/mm/dd,hh:mm:ss(+/-)tz"
+        // tz is in number of quarter-hours
+
+        long start = SystemClock.elapsedRealtime();
+        Log.i(LOG_TAG, "NITZ: " + nitz + "," + nitzReceiveTime +
+                        " start=" + start + " delay=" + (start - nitzReceiveTime));
+
+        try {
+            /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
+             * offset as well (which we won't worry about until later) */
+            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+
+            c.clear();
+            c.set(Calendar.DST_OFFSET, 0);
+
+            String[] nitzSubs = nitz.split("[/:,+-]");
+
+            int year = 2000 + Integer.parseInt(nitzSubs[0]);
+            c.set(Calendar.YEAR, year);
+
+            // month is 0 based!
+            int month = Integer.parseInt(nitzSubs[1]) - 1;
+            c.set(Calendar.MONTH, month);
+
+            int date = Integer.parseInt(nitzSubs[2]);
+            c.set(Calendar.DATE, date);
+
+            int hour = Integer.parseInt(nitzSubs[3]);
+            c.set(Calendar.HOUR, hour);
+
+            int minute = Integer.parseInt(nitzSubs[4]);
+            c.set(Calendar.MINUTE, minute);
+
+            int second = Integer.parseInt(nitzSubs[5]);
+            c.set(Calendar.SECOND, second);
+
+            boolean sign = (nitz.indexOf('-') == -1);
+
+            int tzOffset = Integer.parseInt(nitzSubs[6]);
+
+            int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
+                                              : 0;
+
+            // The zone offset received from NITZ is for current local time,
+            // so DST correction is already applied.  Don't add it again.
+            //
+            // tzOffset += dst * 4;
+            //
+            // We could unapply it if we wanted the raw offset.
+
+            tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
+
+            TimeZone    zone = null;
+
+            // As a special extension, the Android emulator appends the name of
+            // the host computer's timezone to the nitz string. this is zoneinfo
+            // timezone name of the form Area!Location or Area!Location!SubLocation
+            // so we need to convert the ! into /
+            if (nitzSubs.length >= 9) {
+                String  tzname = nitzSubs[8].replace('!','/');
+                zone = TimeZone.getTimeZone( tzname );
+            }
+
+            String iso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY);
+
+            if (zone == null) {
+
+                if (mGotCountryCode) {
+                    if (iso != null && iso.length() > 0) {
+                        zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
+                                c.getTimeInMillis(),
+                                iso);
+                    } else {
+                        // We don't have a valid iso country code.  This is
+                        // most likely because we're on a test network that's
+                        // using a bogus MCC (eg, "001"), so get a TimeZone
+                        // based only on the NITZ parameters.
+                        zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
+                    }
+                }
+            }
+
+            if (zone == null) {
+                // We got the time before the country, so we don't know
+                // how to identify the DST rules yet.  Save the information
+                // and hope to fix it up later.
+
+                mNeedFixZone = true;
+                mZoneOffset  = tzOffset;
+                mZoneDst     = dst != 0;
+                mZoneTime    = c.getTimeInMillis();
+            }
+
+            if (zone != null) {
+                if (getAutoTime()) {
+                    setAndBroadcastNetworkSetTimeZone(zone.getID());
+                }
+                saveNitzTimeZone(zone.getID());
+            }
+
+            String ignore = SystemProperties.get("gsm.ignore-nitz");
+            if (ignore != null && ignore.equals("yes")) {
+                Log.i(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set");
+                return;
+            }
+
+            try {
+                mWakeLock.acquire();
+
+                if (getAutoTime()) {
+                    long millisSinceNitzReceived
+                            = SystemClock.elapsedRealtime() - nitzReceiveTime;
+
+                    if (millisSinceNitzReceived < 0) {
+                        // Sanity check: something is wrong
+                        Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
+                                            + "backwards since NITZ time was received, "
+                                            + nitz);
+                        return;
+                    }
+
+                    if (millisSinceNitzReceived > Integer.MAX_VALUE) {
+                        // If the time is this far off, something is wrong > 24 days!
+                        Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
+                                        + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
+                                        + " days");
+                        return;
+                    }
+
+                    // Note: with range checks above, cast to int is safe
+                    c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
+
+                    Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
+                            + " NITZ receive delay(ms): " + millisSinceNitzReceived
+                        + " gained(ms): "
+                        + (c.getTimeInMillis() - System.currentTimeMillis())
+                            + " from " + nitz);
+
+                    setAndBroadcastNetworkSetTime(c.getTimeInMillis());
+                    Log.i(LOG_TAG, "NITZ: after Setting time of day");
+                }
+                SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
+                saveNitzTime(c.getTimeInMillis());
+                if (Config.LOGV) {
+                    long end = SystemClock.elapsedRealtime();
+                    Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
+                }
+            } finally {
+                mWakeLock.release();
+            }
+        } catch (RuntimeException ex) {
+            Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex);
+        }
+    }
+
     private boolean getAutoTime() {
         try {
             return Settings.System.getInt(phone.getContext().getContentResolver(),
@@ -1132,6 +1332,58 @@
         }
     }
 
+    private void saveNitzTimeZone(String zoneId) {
+        mSavedTimeZone = zoneId;
+    }
+
+    private void saveNitzTime(long time) {
+        mSavedTime = time;
+        mSavedAtTime = SystemClock.elapsedRealtime();
+    }
+
+    /**
+     * Set the timezone and send out a sticky broadcast so the system can
+     * determine if the timezone was set by the carrier.
+     *
+     * @param zoneId timezone set by carrier
+     */
+    private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
+        AlarmManager alarm =
+            (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
+        alarm.setTimeZone(zoneId);
+        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
+        intent.putExtra("time-zone", zoneId);
+        phone.getContext().sendStickyBroadcast(intent);
+    }
+
+    /**
+     * Set the time and Send out a sticky broadcast so the system can determine
+     * if the time was set by the carrier.
+     *
+     * @param time time set by network
+     */
+    private void setAndBroadcastNetworkSetTime(long time) {
+        SystemClock.setCurrentTimeMillis(time);
+        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+        intent.putExtra("time", time);
+        phone.getContext().sendStickyBroadcast(intent);
+    }
+
+     private void revertToNitz() {
+        if (Settings.System.getInt(phone.getContext().getContentResolver(),
+                Settings.System.AUTO_TIME, 0) == 0) {
+            return;
+        }
+        Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone
+                + "' mSavedTime=" + mSavedTime
+                + " mSavedAtTime=" + mSavedAtTime);
+        if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) {
+            setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+            setAndBroadcastNetworkSetTime(mSavedTime
+                    + (SystemClock.elapsedRealtime() - mSavedAtTime));
+        }
+    }
+
     /**
      * @return true if phone is camping on a technology
      * that could support voice and data simultaneously.
@@ -1148,4 +1400,12 @@
         Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
     }
 
+    public String getMdnNumber() {
+        return mMdn;
+    }
+
+    public String getCdmaMin() {
+         return mMin;
+    }
+
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java
index 40358c8..5c8e23e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java
+++ b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java
@@ -23,28 +23,6 @@
     public static final int ROAMING_ICON_MODE_NORMAL    = 0;
     public static final int ROAMING_ICON_MODE_FLASH     = 1;
 
-    /**
-     * TODO(Teleca): These strings appear to be used by the UI
-     * hence they must be changed to resources so they can be
-     * translated to the appropriate language.
-     */
-    public static final String ROAMING_TEXT_0  = "Roaming Indicator On";
-    public static final String ROAMING_TEXT_1  = "Roaming Indicator Off";
-    public static final String ROAMING_TEXT_2  = "Roaming Indicator Flashing";
-    public static final String ROAMING_TEXT_3  = "Out of Neighborhood";
-    public static final String ROAMING_TEXT_4  = "Out of Building";
-    public static final String ROAMING_TEXT_5  = "Roaming - Preferred System";
-    public static final String ROAMING_TEXT_6  = "Roaming - Available System";
-    public static final String ROAMING_TEXT_7  = "Roaming - Alliance Partner";
-    public static final String ROAMING_TEXT_8  = "Roaming - Premium Partner";
-    public static final String ROAMING_TEXT_9  = "Roaming - Full Service Functionality";
-    public static final String ROAMING_TEXT_10 = "Roaming - Partial Service Functionality";
-    public static final String ROAMING_TEXT_11 = "Roaming Banner On";
-    public static final String ROAMING_TEXT_12 = "Roaming Banner Off";
-
-    public static final String SEARCHING_TEXT  = "Searching for Svc.";
-
-
     public int mRoamingIndicator;
     public int mIconIndex;
     public int mIconMode;
diff --git a/telephony/java/com/android/internal/telephony/cdma/EriManager.java b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
index d905e66..0997456 100644
--- a/telephony/java/com/android/internal/telephony/cdma/EriManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
@@ -28,17 +28,12 @@
 import java.util.HashMap;
 
 /**
- * TODO(Teleca): Please as some comments on how this class is to
- * be used. We've removed Handler as a base class and instead
- * recommend that child classes add a Handler as a member if its
- * needed.
+ * EriManager loads the ERI file definitions and manages the CDMA roaming information.
+ *
  */
-
-
 public final class EriManager {
 
     class EriFile {
-        public static final int MAX_ERI_ENTRIES = 30;
 
         public int mVersionNumber;                      // File version number
         public int mNumberOfEriEntries;                 // Number of entries
@@ -55,7 +50,30 @@
             this.mCallPromptId = new String[] { "", "", "" };
             this.mRoamIndTable = new HashMap<Integer, EriInfo>();
         }
+    }
 
+    class EriDisplayInformation {
+        public int mEriIconIndex;
+        public int mEriIconMode;
+        public String mEriIconText;
+
+        public EriDisplayInformation(int eriIconIndex, int eriIconMode, String eriIconText) {
+            mEriIconIndex = eriIconIndex;
+            mEriIconMode = eriIconMode;
+            mEriIconText = eriIconText;
+        }
+
+//        public void setParameters(int eriIconIndex, int eriIconMode, String eriIconText){
+//            this.mEriIconIndex = eriIconIndex;
+//            this.mEriIconMode = eriIconMode;
+//            this.mEriIconText = eriIconText;
+//        }
+
+        @Override
+        public String toString() {
+            return "EriDisplayInformation: {" + " IconIndex: " + mEriIconIndex + " EriIconMode: "
+                    + mEriIconMode + " EriIconText: " + mEriIconText + " }";
+        }
     }
 
     static final String LOG_TAG = "CDMA";
@@ -67,7 +85,7 @@
     private PhoneBase mPhone;
     private Context mContext;
     private int mEriFileSource = ERI_FROM_XML;
-    private boolean isEriFileLoaded = false;
+    private boolean isEriFileLoaded;
     private EriFile mEriFile;
 
     public EriManager(PhoneBase phone, Context context, int eriFileSource) {
@@ -214,11 +232,205 @@
      * Returns the EriInfo record associated with roamingIndicator
      * or null if the entry is not found
      */
-    public EriInfo getEriInfo(int roamingIndicator) {
+    private EriInfo getEriInfo(int roamingIndicator) {
         if (mEriFile.mRoamIndTable.containsKey(roamingIndicator)) {
             return mEriFile.mRoamIndTable.get(roamingIndicator);
         } else {
             return null;
         }
     }
+
+    private EriDisplayInformation getEriDisplayInformation(int roamInd, int defRoamInd){
+        //int iconIndex = -1;
+        //int iconMode = -1;
+        //String iconText = "ERI text";
+        EriDisplayInformation ret;
+
+        switch (roamInd) {
+        // Handling the standard roaming indicator (non-ERI)
+        case EriInfo.ROAMING_INDICATOR_ON:
+            ret = new EriDisplayInformation(
+                    EriInfo.ROAMING_INDICATOR_ON,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText0).toString());
+            break;
+        
+        case EriInfo.ROAMING_INDICATOR_OFF:
+            ret = new EriDisplayInformation(
+                    EriInfo.ROAMING_INDICATOR_OFF,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText1).toString());
+            break;
+
+        case EriInfo.ROAMING_INDICATOR_FLASH:
+            ret = new EriDisplayInformation(
+                    EriInfo.ROAMING_INDICATOR_FLASH,
+                    EriInfo.ROAMING_ICON_MODE_FLASH,
+                    mContext.getText(com.android.internal.R.string.roamingText2).toString());
+            break;
+
+
+        // Handling the standard ERI
+        case 3:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText3).toString());
+            break;
+
+        case 4:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText4).toString());
+            break;
+        
+        case 5:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText5).toString());
+            break;
+        
+        case 6:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText6).toString());
+            break;
+        
+        case 7:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText7).toString());
+            break;
+        
+        case 8:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText8).toString());
+            break;
+        
+        case 9:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText9).toString());
+            break;
+        
+        case 10:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText10).toString());
+            break;
+        
+        case 11:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText11).toString());
+            break;
+        
+        case 12:
+            ret = new EriDisplayInformation(
+                    roamInd,
+                    EriInfo.ROAMING_ICON_MODE_NORMAL,
+                    mContext.getText(com.android.internal.R.string.roamingText12).toString());
+            break;
+
+        // Handling the non standard Enhanced Roaming Indicator (roamInd > 63)
+        default:
+            if (!isEriFileLoaded) {
+                // ERI file NOT loaded
+                Log.d(LOG_TAG, "ERI File not loaded");
+                if(defRoamInd > 2) {
+                    Log.d(LOG_TAG, "ERI defRoamInd > 2 ...flashing");
+                    ret = new EriDisplayInformation(
+                            EriInfo.ROAMING_INDICATOR_FLASH,
+                            EriInfo.ROAMING_ICON_MODE_FLASH,
+                            mContext.getText(com.android.internal
+                                                            .R.string.roamingText2).toString());
+                } else {
+                    Log.d(LOG_TAG, "ERI defRoamInd <= 2");
+                    switch (defRoamInd) {
+                    case EriInfo.ROAMING_INDICATOR_ON:
+                        ret = new EriDisplayInformation(
+                                EriInfo.ROAMING_INDICATOR_ON,
+                                EriInfo.ROAMING_ICON_MODE_NORMAL,
+                                mContext.getText(com.android.internal
+                                                            .R.string.roamingText0).toString());
+                        break;
+                    
+                    case EriInfo.ROAMING_INDICATOR_OFF:
+                        ret = new EriDisplayInformation(
+                                EriInfo.ROAMING_INDICATOR_OFF,
+                                EriInfo.ROAMING_ICON_MODE_NORMAL,
+                                mContext.getText(com.android.internal
+                                                            .R.string.roamingText1).toString());
+                        break;
+                    
+                    case EriInfo.ROAMING_INDICATOR_FLASH:
+                        ret = new EriDisplayInformation(
+                                EriInfo.ROAMING_INDICATOR_FLASH,
+                                EriInfo.ROAMING_ICON_MODE_FLASH,
+                                mContext.getText(com.android.internal
+                                                            .R.string.roamingText2).toString());
+                        break;
+                        
+                    default:
+                        ret = new EriDisplayInformation(-1, -1, "ERI text");
+                    }
+                }
+            } else {
+                // ERI file loaded
+                Log.d(LOG_TAG, "ERI File loaded");
+                EriInfo eriInfo = getEriInfo(roamInd);
+                EriInfo defEriInfo = getEriInfo(defRoamInd);
+                if (eriInfo == null) {
+                    Log.d(LOG_TAG, "ERI roamInd " + roamInd
+                            + " not found in ERI file ...using defRoamInd " + defRoamInd);
+                    if(defEriInfo == null) {
+                        Log.e(LOG_TAG, "ERI defRoamInd " + defRoamInd
+                                + " not found in ERI file ...on");
+                        ret = new EriDisplayInformation(
+                                EriInfo.ROAMING_INDICATOR_ON,
+                                EriInfo.ROAMING_ICON_MODE_NORMAL,
+                                mContext.getText(com.android.internal
+                                                             .R.string.roamingText0).toString());
+
+                    } else {
+                        Log.d(LOG_TAG, "ERI defRoamInd " + defRoamInd + " found in ERI file");
+                        ret = new EriDisplayInformation(
+                                defEriInfo.mIconIndex,
+                                defEriInfo.mIconMode,
+                                defEriInfo.mEriText);
+                    }
+                } else {
+                    Log.d(LOG_TAG, "ERI roamInd " + roamInd + " found in ERI file");
+                    ret = new EriDisplayInformation(
+                            eriInfo.mIconIndex,
+                            eriInfo.mIconMode,
+                            eriInfo.mEriText);
+                }
+            }
+            break;
+        }
+        Log.d(LOG_TAG, "Displaying ERI " + ret.toString());
+        return ret;
+    }
+
+    public int getCdmaEriIconIndex(int roamInd, int defRoamInd){
+        return getEriDisplayInformation(roamInd, defRoamInd).mEriIconIndex;
+    }
+
+    public int getCdmaEriIconMode(int roamInd, int defRoamInd){
+        return getEriDisplayInformation(roamInd, defRoamInd).mEriIconMode;
+    }
+
+    public String getCdmaEriText(int roamInd, int defRoamInd){
+        return getEriDisplayInformation(roamInd, defRoamInd).mEriIconText;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java
index c226b62e..85fe6dc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java
+++ b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java
@@ -84,7 +84,7 @@
 
     CDMAPhone phone;
     Context context;
-
+    CdmaConnection suppConn;
     String action;              // '*' in CDMA
     String sc;                  // Service Code
     String poundString;         // Entire Flash string
@@ -239,8 +239,15 @@
     /** Process a Flash Code...anything that isn't a dialing number */
     void processCode () {
         Log.d(LOG_TAG, "send feature code...");
-        phone.mCM.sendCDMAFeatureCode(this.poundString,
-                obtainMessage(EVENT_CDMA_FLASH_COMPLETED));
+        if (this.poundString != null) {
+            // TODO(Moto): Is suppConn going away?
+            suppConn = new CdmaConnection(phone.getContext(), this.poundString, phone.mCT, null);    
+            phone.mCM.sendCDMAFeatureCode(suppConn.address,
+                 obtainMessage(EVENT_CDMA_FLASH_COMPLETED));
+        } else {
+             phone.mCM.sendCDMAFeatureCode(this.poundString,
+                 obtainMessage(EVENT_CDMA_FLASH_COMPLETED));
+        }
     }
 
     /** Called from CDMAPhone.handleMessage; not a Handler subclass */
@@ -261,6 +268,7 @@
             } else {
                 state = State.COMPLETE;
                 message = context.getText(com.android.internal.R.string.fcComplete);
+                suppConn.processNextPostDialChar();
             }
             phone.onFeatureCodeDone(this);
             break;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 321824f..7edd30f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -39,6 +39,10 @@
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.PhoneProxy;
 
+import com.android.internal.telephony.TelephonyIntents;
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+
 
 /**
  * {@hide}
@@ -47,14 +51,12 @@
     static final String LOG_TAG = "CDMA";
 
     private static final boolean DBG = true;
+    private boolean  m_ota_commited=false;
 
     //***** Instance Variables
 
-    private String mImsi;       // TODO(Teleca): to be checked, if this should be removed!
-    private String mMyMobileNumber;
-    private String mSid;        // TODO(Teleca): Unused should this be removed
-    private String mNid;        // TODO(Teleca): Unused should this be removed
-    private String mMin2Min1;
+    String spn;
+    int spnDisplayCondition;
 
     //***** Event Constants
 
@@ -73,6 +75,7 @@
     private static final int EVENT_GET_SMS_DONE = 22;
 
     private static final int EVENT_RUIM_REFRESH = 31;
+    private static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 32;
 
     RuimRecords(CDMAPhone p) {
         super(p);
@@ -93,6 +96,7 @@
 
         // Start off by setting empty state
         onRadioOffOrNotAvailable();
+        p.mCM.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null);
 
     }
 
@@ -101,6 +105,8 @@
         phone.mCM.unregisterForRUIMReady(this);
         phone.mCM.unregisterForOffOrNotAvailable( this);
         phone.mCM.unSetOnIccRefresh(this);
+        phone.mCM.unregisterForNVReady(this);
+        phone.mCM.unregisterForCdmaOtaProvision(this);
     }
 
     @Override
@@ -125,19 +131,6 @@
         recordsRequested = false;
     }
 
-    /** Returns null if RUIM is not yet ready */
-    public String getIMSI_M() {
-        return mImsi;
-    }
-
-    public String getMdnNumber() {
-        return mMyMobileNumber;
-    }
-
-    public String getMin() {
-         return mMin2Min1;
-    }
-
     @Override
     public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){
         // In CDMA this is Operator/OEM dependent
@@ -162,32 +155,6 @@
         }
     }
 
-    /** 
-     * Returns the 5 or 6 digit MCC/MNC of the operator that
-     *  provided the RUIM card. Returns null of RUIM is not yet ready
-     */
-    public String getRUIMOperatorNumeric() {
-        if (mImsi == null) {
-            return null;
-        }
-
-        if (mncLength != 0) {
-            // Length = length of MCC + length of MNC
-            // TODO: change spec name
-            // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
-            return mImsi.substring(0, 3 + mncLength);
-        }
-
-        // Guess the MNC length based on the MCC if we don't
-        // have a valid value in ef[ad]
-
-        int mcc;
-
-        mcc = Integer.parseInt(mImsi.substring(0,3));
-
-        return mImsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
-    }
-
     @Override
     public void handleMessage(Message msg) {
         AsyncResult ar;
@@ -214,18 +181,35 @@
             /* IO events */
 
             case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
+                // TODO(Moto):TODO(Teleca): This event was removed by Teleca/QCT
+                // I've left it as it's needed to complete EVENT_OTA_PROVISION_STATUS_CHANGE.
+                // But since various instance variables are removed I've commented
+                // out code that references them. I'm sure this is wrong so
+                // Moto/Teleca/QCT need to come to an agreement. Also see onRuimReady
+                // and onVnReady.
+
                 ar = (AsyncResult)msg.obj;
                 String localTemp[] = (String[])ar.result;
                 if (ar.exception != null) {
                     break;
                 }
+                if(m_ota_commited) {
+                    //if(mMyMobileNumber != localTemp[0]) {
+                        Intent intent = new Intent(TelephonyIntents.ACTION_CDMA_OTA_MDN_CHANGED);
+                        intent.putExtra("mdn", localTemp[0]);
+                        Log.d(LOG_TAG,"Broadcasting intent MDN Change in OTA ");
+                        ActivityManagerNative.broadcastStickyIntent(intent, null);
+                    //}
+                    m_ota_commited=false;
+                }
+                //mMyMobileNumber = localTemp[0];
+                //mSid = localTemp[1];
+                //mNid = localTemp[2];
+                //if (localTemp.length >= 3) { // TODO(Moto): remove when new ril always returns min2_min1
+                //   mMin2Min1 = localTemp[3];
+                //}
 
-                mMyMobileNumber = localTemp[0];
-                mSid = localTemp[1];
-                mNid = localTemp[2];
-                mMin2Min1 = localTemp[3];
-
-                Log.d(LOG_TAG, "MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1);
+                //Log.d(LOG_TAG, "MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1);
 
             break;
 
@@ -272,6 +256,19 @@
                 }
                 break;
 
+            case EVENT_OTA_PROVISION_STATUS_CHANGE:
+                m_ota_commited=false;
+                ar = (AsyncResult)msg.obj;
+                if (ar.exception == null) {
+                    int[] ints = (int[]) ar.result;
+                    int otaStatus = ints[0];
+                    if (otaStatus== phone.CDMA_OTA_PROVISION_STATUS_COMMITTED) {
+                        m_ota_commited=true;
+                        phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
+                    }
+                 }
+                 break;
+
         }}catch (RuntimeException exc) {
             // I don't want these exceptions to be fatal
             Log.w(LOG_TAG, "Exception parsing RUIM record", exc);
@@ -318,14 +315,14 @@
                 RuimCard.INTENT_VALUE_ICC_READY, null);
 
         fetchRuimRecords();
-
-        phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
-
+        
+        // TODO(Moto): TODO(Teleca): Work out how to do CDMA subscription
+        // phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
     }
 
     private void onNvReady() {
-        phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
-
+        // TODO(Moto): TODO(Teleca): Work out how to do CDMA subscription
+        // phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));        
     }
 
     private void fetchRuimRecords() {
@@ -374,17 +371,17 @@
 
         switch ((result[0])) {
             case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
- 		        if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
+                if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
                 adnCache.reset();
                 fetchRuimRecords();
                 break;
             case CommandsInterface.SIM_REFRESH_INIT:
-		        if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
+                if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
                 // need to reload all files (that we care about)
                 fetchRuimRecords();
                 break;
             case CommandsInterface.SIM_REFRESH_RESET:
-		        if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
+                if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
                 phone.mCM.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
                 * radio power state is still ON (as tracked by ServiceStateTracker),
@@ -396,7 +393,7 @@
                 break;
             default:
                 // unknown refresh operation
-		        if (DBG) log("handleRuimRefresh with unknown operation");
+                if (DBG) log("handleRuimRefresh with unknown operation");
                 break;
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
new file mode 100644
index 0000000..444dec3
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
@@ -0,0 +1,272 @@
+/*
+ * 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.telephony.cdma;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import android.util.Log;
+import android.media.ToneGenerator;
+
+public class SignalToneUtil {
+    // 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;
+    static public final int IS95_CONST_IR_SIGNAL_IS54B = 2;
+    static public final int IS95_CONST_IR_SIGNAL_USR_DEFD_ALERT = 4;
+
+    // public final int int IS95_CONST_IR_ALERT_PITCH_TYPE;
+    static public final int IS95_CONST_IR_ALERT_MED = 0;
+    static public final int IS95_CONST_IR_ALERT_HIGH = 1;
+    static public final int IS95_CONST_IR_ALERT_LOW = 2;
+    static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 255;
+
+    // public final int int IS95_CONST_IR_SIGNAL_TYPE;
+    static public final int IS95_CONST_IR_SIG_ISDN_NORMAL = 0;
+    static public final int IS95_CONST_IR_SIG_ISDN_INTGRP = 1;
+    static public final int IS95_CONST_IR_SIG_ISDN_SP_PRI = 2;
+    static public final int IS95_CONST_IR_SIG_ISDN_PAT_3 = 3;
+    static public final int IS95_CONST_IR_SIG_ISDN_PING = 4;
+    static public final int IS95_CONST_IR_SIG_ISDN_PAT_5 = 5;
+    static public final int IS95_CONST_IR_SIG_ISDN_PAT_6 = 6;
+    static public final int IS95_CONST_IR_SIG_ISDN_PAT_7 = 7;
+    static public final int IS95_CONST_IR_SIG_ISDN_OFF = 15;
+    static public final int IS95_CONST_IR_SIG_TONE_DIAL = 0;
+    static public final int IS95_CONST_IR_SIG_TONE_RING = 1;
+    static public final int IS95_CONST_IR_SIG_TONE_INT = 2;
+    static public final int IS95_CONST_IR_SIG_TONE_ABB_INT = 3;
+    static public final int IS95_CONST_IR_SIG_TONE_REORDER = 4;
+    static public final int IS95_CONST_IR_SIG_TONE_ABB_RE = 5;
+    static public final int IS95_CONST_IR_SIG_TONE_BUSY = 6;
+    static public final int IS95_CONST_IR_SIG_TONE_CONFIRM = 7;
+    static public final int IS95_CONST_IR_SIG_TONE_ANSWER = 8;
+    static public final int IS95_CONST_IR_SIG_TONE_CALL_W = 9;
+    static public final int IS95_CONST_IR_SIG_TONE_PIP = 10;
+    static public final int IS95_CONST_IR_SIG_TONE_NO_TONE = 63;
+    static public final int IS95_CONST_IR_SIG_IS54B_NO_TONE = 0;
+    static public final int IS95_CONST_IR_SIG_IS54B_L = 1;
+    static public final int IS95_CONST_IR_SIG_IS54B_SS = 2;
+    static public final int IS95_CONST_IR_SIG_IS54B_SSL = 3;
+    static public final int IS95_CONST_IR_SIG_IS54B_SS_2 = 4;
+    static public final int IS95_CONST_IR_SIG_IS54B_SLS = 5;
+    static public final int IS95_CONST_IR_SIG_IS54B_S_X4 = 6;
+    static public final int IS95_CONST_IR_SIG_IS54B_PBX_L = 7;
+    static public final int IS95_CONST_IR_SIG_IS54B_PBX_SS = 8;
+    static public final int IS95_CONST_IR_SIG_IS54B_PBX_SSL = 9;
+    static public final int IS95_CONST_IR_SIG_IS54B_PBX_SLS = 10;
+    static public final int IS95_CONST_IR_SIG_IS54B_PBX_S_X4 = 11;
+    static public final int IS95_CONST_IR_SIG_TONE_ABBR_ALRT = 0;
+
+    // Hashmap to map signalInfo To AudioTone
+    static private HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
+
+    private static Integer signalParamHash(int signalType, int alertPitch, int signal) {
+        // TODO(Moto): The input should get checked before usage
+        return new Integer(signalType * 256 * 256 + alertPitch * 256 + signal);
+    }
+
+    public static int getAudioToneFromSignalInfo(int signalType, int alertPitch, int signal) {
+        int result = ToneGenerator.TONE_CDMA_INVALID;
+        result = hm.get(signalParamHash(signalType, alertPitch, signal));
+        return result;
+    }
+
+    static {
+
+        /* SIGNAL_TYPE_ISDN */
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_ISDN_NORMAL), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                        IS95_CONST_IR_SIG_ISDN_INTGRP),
+                        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);
+
+        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);
+
+        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);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_ISDN_PAT_6), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT6);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_ISDN_PAT_7), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT7);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_ISDN_OFF), ToneGenerator.TONE_CDMA_SIGNAL_OFF);
+
+        /* SIGNAL_TYPE_TONE */
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_DIAL), ToneGenerator.TONE_CDMA_DIAL_TONE_LITE);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_RING), ToneGenerator.TONE_CDMA_NETWORK_USA_RINGBACK);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_INT), ToneGenerator.TONE_SUP_INTERCEPT);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_ABB_INT), ToneGenerator.TONE_SUP_INTERCEPT_ABBREV);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_REORDER), ToneGenerator.TONE_CDMA_REORDER);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_ABB_RE), ToneGenerator.TONE_CDMA_ABBR_REORDER);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_BUSY), ToneGenerator.TONE_CDMA_NETWORK_BUSY);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_CONFIRM), ToneGenerator.TONE_SUP_CONFIRM);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_ANSWER), ToneGenerator.TONE_CDMA_ANSWER);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_ABB_RE), ToneGenerator.TONE_CDMA_NETWORK_CALLWAITING);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_PIP), ToneGenerator.TONE_CDMA_PIP);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_TONE_NO_TONE), ToneGenerator.TONE_CDMA_SIGNAL_OFF);
+
+        /* SIGNAL_TYPE_IS54B */
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                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);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_LOW_L);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_SS), ToneGenerator.TONE_CDMA_HIGH_SS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_SS), ToneGenerator.TONE_CDMA_MED_SS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_SS), ToneGenerator.TONE_CDMA_LOW_SS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_SSL), ToneGenerator.TONE_CDMA_HIGH_SSL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_SSL), ToneGenerator.TONE_CDMA_MED_SSL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_SSL), ToneGenerator.TONE_CDMA_LOW_SSL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_SS_2), ToneGenerator.TONE_CDMA_HIGH_SS_2);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_SS_2), ToneGenerator.TONE_CDMA_MED_SS_2);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_SS_2), ToneGenerator.TONE_CDMA_LOW_SS_2);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_SLS), ToneGenerator.TONE_CDMA_HIGH_SLS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_SLS), ToneGenerator.TONE_CDMA_MED_SLS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_SLS), ToneGenerator.TONE_CDMA_LOW_SLS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_S_X4), ToneGenerator.TONE_CDMA_HIGH_S_X4);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_S_X4), ToneGenerator.TONE_CDMA_MED_S_X4);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_S_X4), ToneGenerator.TONE_CDMA_LOW_S_X4);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_PBX_L), ToneGenerator.TONE_CDMA_HIGH_PBX_L);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_PBX_L), ToneGenerator.TONE_CDMA_MED_PBX_L);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_PBX_L), ToneGenerator.TONE_CDMA_LOW_PBX_L);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_PBX_SS), ToneGenerator.TONE_CDMA_HIGH_PBX_SS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_PBX_SS), ToneGenerator.TONE_CDMA_MED_PBX_SS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_PBX_SS), ToneGenerator.TONE_CDMA_LOW_PBX_SS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_PBX_SSL), ToneGenerator.TONE_CDMA_HIGH_PBX_SSL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_PBX_SSL), ToneGenerator.TONE_CDMA_MED_PBX_SSL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_PBX_SSL), ToneGenerator.TONE_CDMA_LOW_PBX_SSL);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_PBX_SLS), ToneGenerator.TONE_CDMA_HIGH_PBX_SLS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_PBX_SLS), ToneGenerator.TONE_CDMA_MED_PBX_SLS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_PBX_SLS), ToneGenerator.TONE_CDMA_LOW_PBX_SLS);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH,
+                IS95_CONST_IR_SIG_IS54B_PBX_S_X4), ToneGenerator.TONE_CDMA_HIGH_PBX_S_X4);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED,
+                IS95_CONST_IR_SIG_IS54B_PBX_S_X4), ToneGenerator.TONE_CDMA_MED_PBX_S_X4);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW,
+                IS95_CONST_IR_SIG_IS54B_PBX_S_X4), ToneGenerator.TONE_CDMA_LOW_PBX_S_X4);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN,
+                IS95_CONST_IR_SIG_IS54B_NO_TONE), ToneGenerator.TONE_CDMA_SIGNAL_OFF);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_USR_DEFD_ALERT,
+                TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, IS95_CONST_IR_SIG_TONE_ABBR_ALRT),
+                ToneGenerator.TONE_CDMA_ABBR_ALERT);
+
+        hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_USR_DEFD_ALERT,
+                TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, IS95_CONST_IR_SIG_TONE_NO_TONE),
+                ToneGenerator.TONE_CDMA_ABBR_ALERT);
+
+    }
+
+    // suppress default constructor for noninstantiability
+    private SignalToneUtil() {
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index b2083ed..9152559 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -356,39 +356,6 @@
         return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
     }
 
-    static class PduParser {
-
-        PduParser() {
-        }
-
-        /**
-         * Parses an SC timestamp and returns a currentTimeMillis()-style
-         * timestamp
-         */
-        static long getSCTimestampMillis(byte[] timestamp) {
-            // TP-Service-Centre-Time-Stamp
-            int year = IccUtils.beBcdByteToInt(timestamp[0]);
-            int month = IccUtils.beBcdByteToInt(timestamp[1]);
-            int day = IccUtils.beBcdByteToInt(timestamp[2]);
-            int hour = IccUtils.beBcdByteToInt(timestamp[3]);
-            int minute = IccUtils.beBcdByteToInt(timestamp[4]);
-            int second = IccUtils.beBcdByteToInt(timestamp[5]);
-
-            Time time = new Time(Time.TIMEZONE_UTC);
-
-            // C.S0015-B v2.0, 4.5.4: range is 1996-2095
-            time.year = year >= 96 ? year + 1900 : year + 2000;
-            time.month = month - 1;
-            time.monthDay = day;
-            time.hour = hour;
-            time.minute = minute;
-            time.second = second;
-
-            return time.toMillis(true);
-        }
-
-    }
-
     /**
      * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
      */
@@ -557,8 +524,8 @@
                     + originatingAddress.address);
         }
 
-        if (mBearerData.timeStamp != null) {
-                scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp);
+        if (mBearerData.msgCenterTimeStamp != null) {
+            scTimeMillis = mBearerData.msgCenterTimeStamp.toMillis(true);
         }
 
         if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
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 05c8c9d..ab65b0a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -20,6 +20,9 @@
 
 import android.telephony.SmsMessage;
 
+import android.text.format.Time;
+
+import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.cdma.sms.UserData;
@@ -38,15 +41,16 @@
     /**
      * Bearer Data Subparameter Indentifiers
      * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1)
+     * NOTE: Commented subparameter types are not implemented.
      */
     private final static byte SUBPARAM_MESSAGE_IDENTIFIER               = 0x00;
     private final static byte SUBPARAM_USER_DATA                        = 0x01;
     private final static byte SUBPARAM_USER_REPONSE_CODE                = 0x02;
     private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP        = 0x03;
-    //private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE         = 0x04;
-    //private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE         = 0x05;
-    //private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE  = 0x06;
-    //private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE  = 0x07;
+    private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE         = 0x04;
+    private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE         = 0x05;
+    private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE  = 0x06;
+    private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE  = 0x07;
     private final static byte SUBPARAM_PRIORITY_INDICATOR               = 0x08;
     private final static byte SUBPARAM_PRIVACY_INDICATOR                = 0x09;
     private final static byte SUBPARAM_REPLY_OPTION                     = 0x0A;
@@ -56,7 +60,7 @@
     private final static byte SUBPARAM_CALLBACK_NUMBER                  = 0x0E;
     private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE             = 0x0F;
     //private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA      = 0x10;
-    //private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX            = 0x11;
+    private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX            = 0x11;
     //private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA    = 0x12;
     //private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13;
     private final static byte SUBPARAM_MESSAGE_STATUS                   = 0x14;
@@ -205,23 +209,94 @@
      */
     public UserData userData;
 
-    //public UserResponseCode userResponseCode;
+    /**
+     * The User Response Code subparameter is used in the SMS User
+     * Acknowledgment Message to respond to previously received short
+     * messages. This message center-specific element carries the
+     * identifier of a predefined response. (See 3GPP2 C.S.0015-B, v2,
+     * 4.5.3)
+     */
+    public boolean userResponseCodeSet = false;
+    public int userResponseCode;
 
     /**
      * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
-     * year, month, day, hours, minutes, seconds;
      */
-    public byte[] timeStamp;
+    public static class TimeStamp extends Time {
 
-    //public SmsTime validityPeriodAbsolute;
-    //public SmsRelTime validityPeriodRelative;
-    //public SmsTime deferredDeliveryTimeAbsolute;
-    //public SmsRelTime deferredDeliveryTimeRelative;
+        public TimeStamp() {
+            super(Time.TIMEZONE_UTC);
+        }
+
+        public static TimeStamp fromByteArray(byte[] data) {
+            TimeStamp ts = new TimeStamp();
+            // C.S0015-B v2.0, 4.5.4: range is 1996-2095
+            int year = IccUtils.beBcdByteToInt(data[0]);
+            if (year > 99 || year < 0) return null;
+            ts.year = year >= 96 ? year + 1900 : year + 2000;
+            int month = IccUtils.beBcdByteToInt(data[1]);
+            if (month < 1 || month > 12) return null;
+            ts.month = month - 1;
+            int day = IccUtils.beBcdByteToInt(data[2]);
+            if (day < 1 || day > 31) return null;
+            ts.monthDay = day;
+            int hour = IccUtils.beBcdByteToInt(data[3]);
+            if (hour < 0 || hour > 23) return null;
+            ts.hour = hour;
+            int minute = IccUtils.beBcdByteToInt(data[4]);
+            if (minute < 0 || minute > 59) return null;
+            ts.minute = minute;
+            int second = IccUtils.beBcdByteToInt(data[5]);
+            if (second < 0 || second > 59) return null;
+            ts.second = second;
+            return ts;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("TimeStamp ");
+            builder.append("{ year=" + year);
+            builder.append(", month=" + month);
+            builder.append(", day=" + monthDay);
+            builder.append(", hour=" + hour);
+            builder.append(", minute=" + minute);
+            builder.append(", second=" + second);
+            builder.append(" }");
+            return builder.toString();
+        }
+    }
+
+    public TimeStamp msgCenterTimeStamp;
+    public TimeStamp validityPeriodAbsolute;
+    public TimeStamp deferredDeliveryTimeAbsolute;
 
     /**
-     * Reply Option
-     * 1-bit values which indicate whether SMS acknowledgment is requested or not.
-     * (See 3GPP2 C.S0015-B, v2, 4.5.11)
+     * Relative time is specified as one byte, the value of which
+     * falls into a series of ranges, as specified below.  The idea is
+     * that shorter time intervals allow greater precision -- the
+     * value means minutes from zero until the MINS_LIMIT (inclusive),
+     * upon which it means hours until the HOURS_LIMIT, and so
+     * forth. (See 3GPP2 C.S0015-B, v2, 4.5.6-1)
+     */
+    public static final int RELATIVE_TIME_MINS_LIMIT      = 143;
+    public static final int RELATIVE_TIME_HOURS_LIMIT     = 167;
+    public static final int RELATIVE_TIME_DAYS_LIMIT      = 196;
+    public static final int RELATIVE_TIME_WEEKS_LIMIT     = 244;
+    public static final int RELATIVE_TIME_INDEFINITE      = 245;
+    public static final int RELATIVE_TIME_NOW             = 246;
+    public static final int RELATIVE_TIME_MOBILE_INACTIVE = 247;
+    public static final int RELATIVE_TIME_RESERVED        = 248;
+
+    public boolean validityPeriodRelativeSet;
+    public int validityPeriodRelative;
+    public boolean deferredDeliveryTimeRelativeSet;
+    public int deferredDeliveryTimeRelative;
+
+    /**
+     * The Reply Option subparameter contains 1-bit values which
+     * indicate whether SMS acknowledgment is requested or not.  (See
+     * 3GPP2 C.S0015-B, v2, 4.5.11)
      */
     public boolean userAckReq;
     public boolean deliveryAckReq;
@@ -229,14 +304,28 @@
     public boolean reportReq;
 
     /**
-     * The number of Messages element (8-bit value) is a decimal number in the 0 to 99 range
-     * representing the number of messages stored at the Voice Mail System. This element is
-     * used by the Voice Mail Notification service.
-     * (See 3GPP2 C.S0015-B, v2, 4.5.12)
+     * The Number of Messages subparameter (8-bit value) is a decimal
+     * number in the 0 to 99 range representing the number of messages
+     * stored at the Voice Mail System. This element is used by the
+     * Voice Mail Notification service.  (See 3GPP2 C.S0015-B, v2,
+     * 4.5.12)
      */
     public int numberOfMessages;
 
     /**
+     * The Message Deposit Index subparameter is assigned by the
+     * message center as a unique index to the contents of the User
+     * Data subparameter in each message sent to a particular mobile
+     * station. The mobile station, when replying to a previously
+     * received short message which included a Message Deposit Index
+     * subparameter, may include the Message Deposit Index of the
+     * received message to indicate to the message center that the
+     * original contents of the message are to be included in the
+     * reply.  (See 3GPP2 C.S0015-B, v2, 4.5.18)
+     */
+    public int depositIndex;
+
+    /**
      * 4-bit or 8-bit value that indicates the number to be dialed in reply to a
      * received SMS message.
      * (See 3GPP2 C.S0015-B, v2, 4.5.15)
@@ -262,14 +351,23 @@
         builder.append(", language=" + (languageIndicatorSet ? language : "unset"));
         builder.append(", errorClass=" + (messageStatusSet ? errorClass : "unset"));
         builder.append(", msgStatus=" + (messageStatusSet ? messageStatus : "unset"));
-        builder.append(", timeStamp=" +
-                ((timeStamp != null) ? HexDump.toHexString(timeStamp) : "unset"));
+        builder.append(", msgCenterTimeStamp=" +
+                ((msgCenterTimeStamp != null) ? msgCenterTimeStamp : "unset"));
+        builder.append(", validityPeriodAbsolute=" +
+                ((validityPeriodAbsolute != null) ? validityPeriodAbsolute : "unset"));
+        builder.append(", validityPeriodRelative=" +
+                ((validityPeriodRelativeSet) ? validityPeriodRelative : "unset"));
+        builder.append(", deferredDeliveryTimeAbsolute=" +
+                ((deferredDeliveryTimeAbsolute != null) ? deferredDeliveryTimeAbsolute : "unset"));
+        builder.append(", deferredDeliveryTimeRelative=" +
+                ((deferredDeliveryTimeRelativeSet) ? deferredDeliveryTimeRelative : "unset"));
         builder.append(", userAckReq=" + userAckReq);
         builder.append(", deliveryAckReq=" + deliveryAckReq);
         builder.append(", readAckReq=" + readAckReq);
         builder.append(", reportReq=" + reportReq);
         builder.append(", numberOfMessages=" + numberOfMessages);
         builder.append(", callbackNumber=" + callbackNumber);
+        builder.append(", depositIndex=" + depositIndex);
         builder.append(", hasUserDataHeader=" + hasUserDataHeader);
         builder.append(", userData=" + userData);
         builder.append(" }");
@@ -518,11 +616,11 @@
         outStream.write(8, bData.numberOfMessages);
     }
 
-    private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream)
+    private static void encodeValidityPeriodRel(BearerData bData, BitwiseOutputStream outStream)
         throws BitwiseOutputStream.AccessException
     {
-        outStream.write(8, 6);
-        outStream.writeByteArray(6 * 8, bData.timeStamp);
+        outStream.write(8, 1);
+        outStream.write(8, bData.validityPeriodRelative);
     }
 
     private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream)
@@ -595,9 +693,9 @@
                 outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES);
                 encodeMsgCount(bData, outStream);
             }
-            if (bData.timeStamp != null) {
-                outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP);
-                encodeMsgCenterTimeStamp(bData, outStream);
+            if (bData.validityPeriodRelativeSet) {
+                outStream.write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE);
+                encodeValidityPeriodRel(bData, outStream);
             }
             if (bData.privacyIndicatorSet) {
                 outStream.write(8, SUBPARAM_PRIVACY_INDICATOR);
@@ -791,6 +889,15 @@
         bData.numberOfMessages = inStream.read(8);
     }
 
+    private static void decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
+        throws BitwiseInputStream.AccessException, CodingException
+    {
+        if (inStream.read(8) != 2) {
+            throw new CodingException("MESSAGE_DEPOSIT_INDEX subparam size incorrect");
+        }
+        bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
+    }
+
     private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
         throws CodingException
     {
@@ -863,14 +970,51 @@
         bData.messageStatusSet = true;
     }
 
-    private static void decodeMsgCenterTimeStamp(BearerData bData,
-                                                 BitwiseInputStream inStream)
+    private static void decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
         throws BitwiseInputStream.AccessException, CodingException
     {
         if (inStream.read(8) != 6) {
             throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect");
         }
-        bData.timeStamp = inStream.readByteArray(6 * 8);
+        bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+    }
+
+    private static void decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
+        throws BitwiseInputStream.AccessException, CodingException
+    {
+        if (inStream.read(8) != 6) {
+            throw new CodingException("VALIDITY_PERIOD_ABSOLUTE subparam size incorrect");
+        }
+        bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+    }
+
+    private static void decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
+        throws BitwiseInputStream.AccessException, CodingException
+    {
+        if (inStream.read(8) != 6) {
+            throw new CodingException("DEFERRED_DELIVERY_TIME_ABSOLUTE subparam size incorrect");
+        }
+        bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+    }
+
+    private static void decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
+        throws BitwiseInputStream.AccessException, CodingException
+    {
+        if (inStream.read(8) != 1) {
+            throw new CodingException("VALIDITY_PERIOD_RELATIVE subparam size incorrect");
+        }
+        bData.deferredDeliveryTimeRelative = inStream.read(8);
+        bData.deferredDeliveryTimeRelativeSet = true;
+    }
+
+    private static void decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
+        throws BitwiseInputStream.AccessException, CodingException
+    {
+        if (inStream.read(8) != 1) {
+            throw new CodingException("DEFERRED_DELIVERY_TIME_RELATIVE subparam size incorrect");
+        }
+        bData.validityPeriodRelative = inStream.read(8);
+        bData.validityPeriodRelativeSet = true;
     }
 
     private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
@@ -927,6 +1071,16 @@
         bData.alertIndicatorSet = true;
     }
 
+    private static void decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
+        throws BitwiseInputStream.AccessException, CodingException
+    {
+        if (inStream.read(8) != 1) {
+            throw new CodingException("USER_REPONSE_CODE subparam size incorrect");
+        }
+        bData.userResponseCode = inStream.read(8);
+        bData.userResponseCodeSet = true;
+    }
+
     /**
      * Create BearerData object from serialized representation.
      * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
@@ -955,6 +1109,9 @@
                 case SUBPARAM_USER_DATA:
                     decodeUserData(bData, inStream);
                     break;
+                case SUBPARAM_USER_REPONSE_CODE:
+                    decodeUserResponseCode(bData, inStream);
+                    break;
                 case SUBPARAM_REPLY_OPTION:
                     decodeReplyOption(bData, inStream);
                     break;
@@ -970,6 +1127,18 @@
                 case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
                     decodeMsgCenterTimeStamp(bData, inStream);
                     break;
+                case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
+                    decodeValidityAbs(bData, inStream);
+                    break;
+                case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
+                    decodeValidityRel(bData, inStream);
+                    break;
+                case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
+                    decodeDeferredDeliveryAbs(bData, inStream);
+                    break;
+                case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
+                    decodeDeferredDeliveryRel(bData, inStream);
+                    break;
                 case SUBPARAM_PRIVACY_INDICATOR:
                     decodePrivacyIndicator(bData, inStream);
                     break;
@@ -985,6 +1154,9 @@
                 case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
                     decodeMsgDeliveryAlert(bData, inStream);
                     break;
+                case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
+                    decodeDepositIndex(bData, inStream);
+                    break;
                 default:
                     throw new CodingException("unsupported bearer data subparameter ("
                                               + subparamId + ")");
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
index 440debb..917ec9d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
@@ -20,23 +20,31 @@
 import com.android.internal.util.HexDump;
 
 public class CdmaSmsAddress extends SmsAddress {
+
     /**
-     * digit mode indicators
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+     * Digit Mode Indicator is a 1-bit value that indicates whether
+     * the address digits are 4-bit DTMF codes or 8-bit codes.  (See
+     * 3GPP2 C.S0015-B, v2, 3.4.3.3)
      */
     static public final int DIGIT_MODE_4BIT_DTMF              = 0x00;
     static public final int DIGIT_MODE_8BIT_CHAR              = 0x01;
 
+    public byte digitMode;
+
     /**
-     * number mode indicators
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+     * Number Mode Indicator is 1-bit value that indicates whether the
+     * address type is a data network address or not.  (See 3GPP2
+     * C.S0015-B, v2, 3.4.3.3)
      */
     static public final int NUMBER_MODE_NOT_DATA_NETWORK      = 0x00;
     static public final int NUMBER_MODE_DATA_NETWORK          = 0x01;
 
+    public byte numberMode;
+
     /**
-     *  number types for data networks
-     *  (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+     * Number Types for data networks.
+     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+     * NOTE: value is stored in the parent class ton field.
      */
     static public final int TON_UNKNOWN                   = 0x00;
     static public final int TON_INTERNATIONAL_OR_IP       = 0x01;
@@ -48,65 +56,51 @@
     static public final int TON_RESERVED                  = 0x07;
 
     /**
-     *  maximum lengths for fields as defined in ril_cdma_sms.h
+     * Maximum lengths for fields as defined in ril_cdma_sms.h.
      */
     static public final int SMS_ADDRESS_MAX          =  36;
     static public final int SMS_SUBADDRESS_MAX       =  36;
 
     /**
-     *  Supported numbering plan identification
-     *  (See C.S005-D, v1.0, table 2.7.1.3.2.4-3)
-     */
-    static public final int NUMBERING_PLAN_UNKNOWN           = 0x0;
-    static public final int NUMBERING_PLAN_ISDN_TELEPHONY    = 0x1;
-    //static protected final int NUMBERING_PLAN_DATA              = 0x3;
-    //static protected final int NUMBERING_PLAN_TELEX             = 0x4;
-    //static protected final int NUMBERING_PLAN_PRIVATE           = 0x9;
-
-    /**
-     * 1-bit value that indicates whether the address digits are 4-bit DTMF codes
-     * or 8-bit codes.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
-     */
-    public byte digitMode;
-
-    /**
-     * 1-bit value that indicates whether the address type is a data network address or not.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
-     */
-    public byte numberMode;
-
-    // use parent class member ton instead public byte numberType;
-
-    /**
-     * 0 or 4-bit value that indicates which numbering plan identification is set.
-     * (See 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
-     */
-    public byte numberPlan;
-
-    /**
      * This field shall be set to the number of address digits
      * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
      */
     public byte numberOfDigits;
 
-    // use parent class member orig_bytes instead of public byte[] digits;
+    /**
+     * Numbering Plan identification is a 0 or 4-bit value that
+     * indicates which numbering plan identification is set.  (See
+     * 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
+     */
+    static public final int NUMBERING_PLAN_UNKNOWN           = 0x0;
+    static public final int NUMBERING_PLAN_ISDN_TELEPHONY    = 0x1;
+    //static protected final int NUMBERING_PLAN_DATA              = 0x3;
+    //static protected final int NUMBERING_PLAN_TELEX             = 0x4;
+    //static protected final int NUMBERING_PLAN_PRIVATE           = 0x9;
 
-    // Constructor
+    public byte numberPlan;
+
+    /**
+     * NOTE: the parsed string address and the raw byte array values
+     * are stored in the parent class address and origBytes fields,
+     * respectively.
+     */
+
     public CdmaSmsAddress(){
     }
 
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-        builder.append("CdmaSmsAddress:\n");
-        builder.append("  digitMode: " + digitMode + "\n");
-        builder.append("  numberMode: " + numberMode + "\n");
-        builder.append("  numberPlan: " + numberPlan + "\n");
-        builder.append("  numberOfDigits: " + numberOfDigits + "\n");
-        builder.append("  ton: " + ton + "\n");
-        builder.append("  address: " + address + "\n");
-        builder.append("  origBytes: " + HexDump.toHexString(origBytes) + "\n");
+        builder.append("CdmaSmsAddress ");
+        builder.append("{ digitMode=" + digitMode);
+        builder.append(", numberMode=" + numberMode);
+        builder.append(", numberPlan=" + numberPlan);
+        builder.append(", numberOfDigits=" + numberOfDigits);
+        builder.append(", ton=" + ton);
+        builder.append(", address=" + address);
+        builder.append(", origBytes=" + HexDump.toHexString(origBytes));
+        builder.append(" }");
         return builder.toString();
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 3459dcd..70d71fc 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -878,11 +878,6 @@
         return ret;
     }
 
-    public String getMin() {
-        Log.e(LOG_TAG, "[GSMPhone] getMin() is a CDMA method");
-        return "0";
-    }
-
     public String getDeviceId() {
         return mImei;
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 49e2daf..6e4a495 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -151,7 +151,6 @@
 
     private static final int POLL_PDP_MILLIS = 5 * 1000;
 
-    //WINK:TODO: Teleca, is this really gsm specific, what about CDMA?
     private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect";
     private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
 
@@ -585,8 +584,7 @@
         if ((state == State.IDLE || state == State.SCANNING)
                 && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
                 && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded()
-                && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() ||
-                     phone.getState() == Phone.State.IDLE )
+                && phone.getState() == Phone.State.IDLE
                 && isDataAllowed()
                 && !mIsPsRestricted
                 && desiredPowerState ) {
@@ -1221,7 +1219,7 @@
         if (state == State.FAILED) {
             cleanUpConnection(false, null);
         }
-        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onEnableNewApn() {
@@ -1230,8 +1228,8 @@
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
-    protected void onTrySetupData() {
-        trySetupData(null);
+    protected void onTrySetupData(String reason) {
+        trySetupData(reason);
     }
 
     protected void onRestoreDefaultApn() {
@@ -1363,7 +1361,10 @@
                 } else {
                     // we still have more apns to try
                     setState(State.SCANNING);
-                    trySetupData(reason);
+                    // Wait a bit before trying the next APN, so that
+                    // we're not tying up the RIL command channel
+                    sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
+                            RECONNECT_DELAY_INITIAL_MILLIS);
                 }
             } else {
                 startDelayedRetry(cause, reason);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 699142a..8bf5d19 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -22,12 +22,14 @@
 import android.content.Intent;
 import android.os.AsyncResult;
 import android.os.Message;
+import android.provider.Telephony.Sms.Intents;
 import android.telephony.ServiceState;
 import android.util.Config;
 import android.util.Log;
 
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.gsm.SmsMessage;
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.SMSDispatcher;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
@@ -78,7 +80,7 @@
         }
 
         if (mCm != null) {
-            mCm.acknowledgeLastIncomingSMS(true, null);
+            mCm.acknowledgeLastIncomingGsmSms(true, Intents.RESULT_SMS_HANDLED, null);
         }
     }
 
@@ -150,7 +152,13 @@
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
             concatRef.msgCount = msgCount;
-            concatRef.isEightBits = false;
+            // TODO: We currently set this to true since our messaging app will never
+            // send more than 255 parts (it converts the message to MMS well before that).
+            // However, we should support 3rd party messaging apps that might need 16-bit
+            // references
+            // Note:  It's not sufficient to just flip this bit to true; it will have
+            // ripple effects (several calculations assume 8-bit ref).
+            concatRef.isEightBits = true;
             SmsHeader smsHeader = new SmsHeader();
             smsHeader.concatRef = concatRef;
 
@@ -284,10 +292,10 @@
     }
 
     /** {@inheritDoc} */
-    protected void acknowledgeLastIncomingSms(boolean success, Message response){
+    protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
         // FIXME unit test leaves cm == null. this should change
         if (mCm != null) {
-            mCm.acknowledgeLastIncomingSMS(success, response);
+            mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response);
         }
     }
 
@@ -312,4 +320,17 @@
         response.recycle();
     }
 
+    private int resultToCause(int rc) {
+        switch (rc) {
+            case Activity.RESULT_OK:
+            case Intents.RESULT_SMS_HANDLED:
+                // Cause code is ignored on success.
+                return 0;
+            case Intents.RESULT_SMS_OUT_OF_MEMORY:
+                return CommandsInterface.GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED;
+            case Intents.RESULT_SMS_GENERIC_ERROR:
+            default:
+                return CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR;
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 7a4ea64..63b6a5e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -75,13 +75,6 @@
  */
 final class GsmServiceStateTracker extends ServiceStateTracker {
 
-    /**
-     * TODO(Teleca): John Huang asks: Will you be adding handling of
-     * "reason for registration denied in EVENT_POLL_STATE_REGISTRATION?
-     * I see some handling of this in CdmaServiceStateTracker, but as I
-     * understand it this field was added at the request of a GSM carrier.
-     */
-
     //***** Instance Variables
     GSMPhone phone;
     GsmCellLocation cellLoc;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index ed61c3f..6435be5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -250,6 +250,12 @@
 
             // TP-Data-Coding-Scheme
             // Default encoding, uncompressed
+            // To test writing messages to the SIM card, change this value 0x00
+            // to 0x12, which means "bits 1 and 0 contain message class, and the
+            // class is 2". Note that this takes effect for the sender. In other
+            // words, messages sent by the phone with this change will end up on
+            // the receiver's SIM card. You can then send messages to yourself
+            // (on a phone with this change) and they'll end up on the SIM card.
             bo.write(0x00);
 
             // (no TP-Validity-Period)
@@ -558,9 +564,10 @@
             int offset = cur;
             int userDataLength = pdu[offset++] & 0xff;
             int headerSeptets = 0;
+            int userDataHeaderLength = 0;
 
             if (hasUserDataHeader) {
-                int userDataHeaderLength = pdu[offset++] & 0xff;
+                userDataHeaderLength = pdu[offset++] & 0xff;
 
                 byte[] udh = new byte[userDataHeaderLength];
                 System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength);
@@ -573,19 +580,34 @@
                 mUserDataSeptetPadding = (headerSeptets * 7) - headerBits;
             }
 
-            /*
-             * Here we just create the user data length to be the remainder of
-             * the pdu minus the user data hearder. This is because the count
-             * could mean the number of uncompressed sepets if the userdata is
-             * encoded in 7-bit.
-             */
-            userData = new byte[pdu.length - offset];
+            int bufferLen;
+            if (dataInSeptets) {
+                /*
+                 * Here we just create the user data length to be the remainder of
+                 * the pdu minus the user data header, since userDataLength means
+                 * the number of uncompressed sepets.
+                 */
+                bufferLen = pdu.length - offset;
+            } else {
+                /*
+                 * userDataLength is the count of octets, so just subtract the
+                 * user data header.
+                 */
+                bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0);
+                if (bufferLen < 0) {
+                    bufferLen = 0;
+                }
+            }
+
+            userData = new byte[bufferLen];
             System.arraycopy(pdu, offset, userData, 0, userData.length);
             cur = offset;
 
             if (dataInSeptets) {
                 // Return the number of septets
-                return userDataLength - headerSeptets;
+                int count = userDataLength - headerSeptets;
+                // If count < 0, return 0 (means UDL was probably incorrect)
+                return count < 0 ? 0 : count;
             } else {
                 // Return the number of octets
                 return userData.length;
@@ -615,8 +637,6 @@
         /**
          * Returns an object representing the user data headers
          *
-         * @return an object representing the user data headers
-         *
          * {@hide}
          */
         SmsHeader getUserDataHeader() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java
index 3de14f0..8f0addc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java
+++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java
@@ -184,9 +184,6 @@
         mCmdIf.unSetOnStkCallSetUp(this);
 
         this.removeCallbacksAndMessages(null);
-
-        //removing instance
-        sInstance = null;
     }
 
     protected void finalize() {
@@ -450,7 +447,7 @@
     }
 
     /**
-     * Used for instantiating the Service from the GsmPhone constructor.
+     * Used for instantiating/updating the Service from the GsmPhone constructor.
      *
      * @param ci CommandsInterface object
      * @param sr SIMRecords object
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 42bb2e0..9fb9be8 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -1018,6 +1018,10 @@
         unimplemented(result);
     }
 
+    public void reportSmsMemoryStatus(boolean available, Message result) {
+        unimplemented(result);
+    }
+
     private boolean isSimLocked() {
         if (mSimLockedState != SimLockState.NONE) {
             return true;
@@ -1041,11 +1045,11 @@
     }
 
 
-    public void acknowledgeLastIncomingSMS(boolean success, Message result) {
+    public void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) {
         unimplemented(result);
     }
 
-    public void acknowledgeLastIncomingCdmaSms(boolean success, Message result) {
+    public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) {
         unimplemented(result);
     }
 
@@ -1137,7 +1141,7 @@
             String number, Message result) {unimplemented(result);}
 
     public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);}
-
+    public void exitEmergencyCallbackMode(Message result) {unimplemented(result);}
     public void setNetworkSelectionModeManual(
             String operatorNumeric, Message result) {unimplemented(result);}
 
@@ -1460,10 +1464,6 @@
 
     }
 
-    public void exitEmergencyCallbackMode(Message response) {
-        // TODO method stub
-    }
-
     public void forceDataDormancy(Message response) {
         // TODO method stub
     }
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java
index d5e64596..6658fb0 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/android/test/InstrumentationTestRunner.java
@@ -118,7 +118,8 @@
  * <b>To generate EMMA code coverage:</b>
  * -e coverage true
  * Note: this requires an emma instrumented build. By default, the code coverage results file 
- * will be saved as /sdcard/coverage.ec, unless overridden by coverageFile flag (see below)
+ * will be saved in a /data/<app>/coverage.ec file, unless overridden by coverageFile flag (see
+ * below)
  * <p/>
  * <b> To specify EMMA code coverage results file path:</b>
  * -e coverageFile /sdcard/myFile.ec
@@ -218,6 +219,11 @@
      */
     private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment";
     /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * identifies the path to the generated code coverage file.
+     */
+    private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath";
+    /**
      * The test is starting.
      */
     public static final int REPORT_VALUE_RESULT_START = 1;
@@ -240,7 +246,8 @@
      */
     public static final String REPORT_KEY_STACK = "stack";
 
-    private static final String DEFAULT_COVERAGE_FILE_PATH = "/sdcard/coverage.ec";
+    // Default file name for code coverage
+    private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec";
     
     private static final String LOG_TAG = "InstrumentationTestRunner";
 
@@ -456,14 +463,20 @@
     private void generateCoverageReport() {
         // use reflection to call emma dump coverage method, to avoid
         // always statically compiling against emma jar
-        java.io.File coverageFile = new java.io.File(getCoverageFilePath());
+        String coverageFilePath = getCoverageFilePath();
+        java.io.File coverageFile = new java.io.File(coverageFilePath);
         try {
             Class emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
             Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData", 
                     coverageFile.getClass(), boolean.class, boolean.class);
             
             dumpCoverageMethod.invoke(null, coverageFile, false, false);
-
+            // output path to generated coverage file so it can be parsed by a test harness if
+            // needed
+            mResults.putString(REPORT_KEY_COVERAGE_PATH, coverageFilePath);
+            // also output a more user friendly msg
+            mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                String.format("Generated code coverage data to %s", coverageFilePath));
         } catch (ClassNotFoundException e) {
             reportEmmaError("Is emma jar on classpath?", e);
         } catch (SecurityException e) {
@@ -481,8 +494,9 @@
 
     private String getCoverageFilePath() {
         if (mCoverageFilePath == null) {
-            return DEFAULT_COVERAGE_FILE_PATH;
-        }
+            return getTargetContext().getFilesDir().getAbsolutePath() + File.separator +
+                    DEFAULT_COVERAGE_FILE_NAME;
+         }
         else {
             return mCoverageFilePath;
         }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 75fd157..16aca4d 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -33,7 +33,7 @@
 import android.util.Log;
 
 public class CdmaSmsTest extends AndroidTestCase {
-    private final static String LOG_TAG = "Cdma_Sms_Test";
+    private final static String LOG_TAG = "CDMA";
 
     @SmallTest
     public void testUserData7bitGsm() throws Exception {
@@ -136,6 +136,100 @@
     }
 
     @SmallTest
+    public void testMonolithicOne() throws Exception {
+        String pdu = "0003200010010410168d2002010503060812011101590501c706069706180000000701c108" +
+                "01c00901800a01e00b01030c01c00d01070e05039acc13880f018011020566";
+        BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu));
+        assertEquals(bearerData.messageType, BearerData.MESSAGE_TYPE_SUBMIT);
+        assertEquals(bearerData.messageId, 1);
+        assertEquals(bearerData.priority, BearerData.PRIORITY_EMERGENCY);
+        assertEquals(bearerData.privacy, BearerData.PRIVACY_CONFIDENTIAL);
+        assertEquals(bearerData.userAckReq, true);
+        assertEquals(bearerData.readAckReq, true);
+        assertEquals(bearerData.deliveryAckReq, true);
+        assertEquals(bearerData.reportReq, false);
+        assertEquals(bearerData.numberOfMessages, 3);
+        assertEquals(bearerData.alert, BearerData.ALERT_HIGH_PRIO);
+        assertEquals(bearerData.language, BearerData.LANGUAGE_HEBREW);
+        assertEquals(bearerData.callbackNumber.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+        assertEquals(bearerData.callbackNumber.numberMode,
+                     CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+        assertEquals(bearerData.callbackNumber.ton, CdmaSmsAddress.TON_UNKNOWN);
+        assertEquals(bearerData.callbackNumber.numberPlan, CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN);
+        assertEquals(bearerData.callbackNumber.numberOfDigits, 7);
+        assertEquals(bearerData.callbackNumber.address, "3598271");
+        assertEquals(bearerData.displayMode, BearerData.DISPLAY_MODE_USER);
+        assertEquals(bearerData.depositIndex, 1382);
+        assertEquals(bearerData.userResponseCode, 5);
+        assertEquals(bearerData.msgCenterTimeStamp.year, 2008);
+        assertEquals(bearerData.msgCenterTimeStamp.month, 11);
+        assertEquals(bearerData.msgCenterTimeStamp.monthDay, 1);
+        assertEquals(bearerData.msgCenterTimeStamp.hour, 11);
+        assertEquals(bearerData.msgCenterTimeStamp.minute, 1);
+        assertEquals(bearerData.msgCenterTimeStamp.second, 59);
+        assertEquals(bearerData.validityPeriodAbsolute, null);
+        assertEquals(bearerData.validityPeriodRelative, -63);
+        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.hasUserDataHeader, false);
+        assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII);
+        assertEquals(bearerData.userData.numFields, 2);
+        assertEquals(bearerData.userData.payloadStr, "hi");
+    }
+
+    @SmallTest
+    public void testMonolithicTwo() throws Exception {
+        String pdu = "0003200010010410168d200201050306081201110159050192060697061800000007013d0" +
+                "801c00901800a01e00b01030c01c00d01070e05039acc13880f018011020566";
+        BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu));
+        assertEquals(bearerData.messageType, BearerData.MESSAGE_TYPE_SUBMIT);
+        assertEquals(bearerData.messageId, 1);
+        assertEquals(bearerData.priority, BearerData.PRIORITY_EMERGENCY);
+        assertEquals(bearerData.privacy, BearerData.PRIVACY_CONFIDENTIAL);
+        assertEquals(bearerData.userAckReq, true);
+        assertEquals(bearerData.readAckReq, true);
+        assertEquals(bearerData.deliveryAckReq, true);
+        assertEquals(bearerData.reportReq, false);
+        assertEquals(bearerData.numberOfMessages, 3);
+        assertEquals(bearerData.alert, BearerData.ALERT_HIGH_PRIO);
+        assertEquals(bearerData.language, BearerData.LANGUAGE_HEBREW);
+        assertEquals(bearerData.callbackNumber.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+        assertEquals(bearerData.callbackNumber.numberMode,
+                     CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+        assertEquals(bearerData.callbackNumber.ton, CdmaSmsAddress.TON_UNKNOWN);
+        assertEquals(bearerData.callbackNumber.numberPlan, CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN);
+        assertEquals(bearerData.callbackNumber.numberOfDigits, 7);
+        assertEquals(bearerData.callbackNumber.address, "3598271");
+        assertEquals(bearerData.displayMode, BearerData.DISPLAY_MODE_USER);
+        assertEquals(bearerData.depositIndex, 1382);
+        assertEquals(bearerData.userResponseCode, 5);
+        assertEquals(bearerData.msgCenterTimeStamp.year, 2008);
+        assertEquals(bearerData.msgCenterTimeStamp.month, 11);
+        assertEquals(bearerData.msgCenterTimeStamp.monthDay, 1);
+        assertEquals(bearerData.msgCenterTimeStamp.hour, 11);
+        assertEquals(bearerData.msgCenterTimeStamp.minute, 1);
+        assertEquals(bearerData.msgCenterTimeStamp.second, 59);
+        assertEquals(bearerData.validityPeriodAbsolute, null);
+        assertEquals(bearerData.validityPeriodRelative, 61);
+        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, -110);
+        assertEquals(bearerData.hasUserDataHeader, false);
+        assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII);
+        assertEquals(bearerData.userData.numFields, 2);
+        assertEquals(bearerData.userData.payloadStr, "hi");
+    }
+
+    @SmallTest
     public void testUserDataHeaderConcatRefFeedback() throws Exception {
         BearerData bearerData = new BearerData();
         bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
@@ -410,22 +504,6 @@
     }
 
     @SmallTest
-    public void testMsgCenterTimeStampFeedback() throws Exception {
-        BearerData bearerData = new BearerData();
-        bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
-        bearerData.messageId = 0;
-        bearerData.hasUserDataHeader = false;
-        UserData userData = new UserData();
-        userData.payloadStr = "test message center timestamp";
-        bearerData.userData = userData;
-        bearerData.timeStamp = HexDump.hexStringToByteArray("112233445566");
-        byte []encodedSms = BearerData.encode(bearerData);
-        BearerData revBearerData = BearerData.decode(encodedSms);
-        assertEquals(HexDump.toHexString(bearerData.timeStamp),
-                     HexDump.toHexString(revBearerData.timeStamp));
-    }
-
-    @SmallTest
     public void testPrivacyIndicator() throws Exception {
         String pdu1 = "0003104090010c485f4194dfea34becf61b840090140";
         BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
index 508afcf..5161f7b 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
@@ -17,16 +17,17 @@
 package com.android.unit_tests.os;
 
 import android.os.MemoryFile;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
-import junit.framework.TestCase;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.IOException;
-
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
 
 public class MemoryFileTest extends TestCase {
 
@@ -94,6 +95,74 @@
         file.close();
     }
 
+    // Tests that close() is idempotent
+    @SmallTest
+    public void testCloseClose() throws Exception {
+        MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
+        byte[] data = new byte[512];
+        file.writeBytes(data, 0, 0, 128);
+        file.close();
+        file.close();
+    }
+
+    // Tests that we can't read from a closed memory file
+    @SmallTest
+    public void testCloseRead() throws Exception {
+        MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
+        file.close();
+
+        try {
+            byte[] data = new byte[512];
+            assertEquals(128, file.readBytes(data, 0, 0, 128));
+            fail("readBytes() after close() did not throw IOException.");
+        } catch (IOException e) {
+            // this is what should happen
+        }
+    }
+
+    // Tests that we can't write to a closed memory file
+    @SmallTest
+    public void testCloseWrite() throws Exception {
+        MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
+        file.close();
+
+        try {
+            byte[] data = new byte[512];
+            file.writeBytes(data, 0, 0, 128);
+            fail("writeBytes() after close() did not throw IOException.");
+        } catch (IOException e) {
+            // this is what should happen
+        }
+    }
+
+    // Tests that we can't call allowPurging() after close()
+    @SmallTest
+    public void testCloseAllowPurging() throws Exception {
+        MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
+        byte[] data = new byte[512];
+        file.writeBytes(data, 0, 0, 128);
+        file.close();
+
+        try {
+            file.allowPurging(true);
+            fail("allowPurging() after close() did not throw IOException.");
+        } catch (IOException e) {
+            // this is what should happen
+        }
+    }
+
+    // Tests that we don't leak file descriptors or mmap areas
+    @LargeTest
+    public void testCloseLeak() throws Exception {
+        // open enough memory files that we should run out of
+        // file descriptors or address space if we leak either.
+        for (int i = 0; i < 1025; i++) {
+            MemoryFile file = new MemoryFile("MemoryFileTest", 5000000);
+            file.writeBytes(testString, 0, 0, testString.length);
+            file.close();
+        }
+    }
+
     private static final byte[] testString = new byte[] {
         3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4,
         0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2, 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8, 2, 2, 3, 1, 7, 2,
diff --git a/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java b/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
index e2336f8..3a9c511 100644
--- a/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
@@ -41,7 +41,7 @@
                 SmsHeader.toByteArray(header));
         int septetCount = GsmAlphabet.countGsmSeptets(message, false);
         String parsedMessage = GsmAlphabet.gsm7BitPackedToString(
-                userData, SmsHeader.toByteArray(header).length+1, septetCount, 1);
+                userData, SmsHeader.toByteArray(header).length+2, septetCount, 1);
         assertEquals(message, parsedMessage);
     }
 
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
index 5442ec9..efa41131 100644
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -23,8 +23,8 @@
                 <category android:name="android.intent.category.TEST" />
             </intent-filter>
         </activity>
-        <activity android:name="TestShellActivity" android:launchMode="singleTop">
-        </activity>
+        <activity android:name="TestShellActivity" android:launchMode="singleTop" />
+        <activity android:name="ReliabilityTestActivity" />
     </application>
 
     <instrumentation android:name=".LayoutTestsAutoRunner"
@@ -33,4 +33,5 @@
     />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.WRITE_SDCARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 </manifest>
diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py
index a242293..c12c783 100755
--- a/tests/DumpRenderTree/assets/run_reliability_tests.py
+++ b/tests/DumpRenderTree/assets/run_reliability_tests.py
@@ -10,10 +10,8 @@
 
 import logging
 import optparse
-import random
 import subprocess
 import sys
-import time
 
 TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt"
 TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt"
@@ -41,40 +39,16 @@
   return adb_output.strip() == "#DONE"
 
 
-def RandomPick(file_name, approx_size, num_needed):
-  """Randomly pick lines from the text file specifed.
-
-  Args:
-    file_name: the text file where lines should be picked from
-    approx_size: an approximate size of the text file
-    num_needed: how many lines are needed from the file
-
-  Returns:
-    an array of string
-  """
-  p = float(num_needed) / approx_size
-  num_picked = 0
-  lines = []
-  random.seed()
-
-  while num_picked < num_needed:
-    file_handle = open(file_name, "r")
-    for line in file_handle:
-      line = line.strip()
-      if float(random.randint(0, approx_size)) / approx_size < p:
-        lines.append(line)
-        num_picked += 1
-        if num_picked == num_needed:
-          break
-    file_handle.close()
-  return lines
+def RemoveDeviceFile(adb_cmd, file_name):
+  shell_cmd_str = adb_cmd + " shell rm " + file_name
+  subprocess.Popen(shell_cmd_str,
+                   shell=True, stdout=subprocess.PIPE,
+                   stderr=subprocess.PIPE).communicate()
 
 
 def main(options, args):
   """Send the url list to device and start testing, restart if crashed."""
 
-  generate_url = False
-
   # Set up logging format.
   log_level = logging.INFO
   if options.verbose:
@@ -84,34 +58,23 @@
 
   # Include all tests if none are specified.
   if not args:
-    path = "/tmp/url_list_%d.txt" % time.time()
-    generate_url = True
-    logging.info("A URL list is not provided, will be automatically generated.")
+    print "Missing URL list file"
+    sys.exit(1)
   else:
     path = args[0]
 
   if not options.crash_file:
-    print "missing crash file name, use --crash-file to specify"
+    print "Missing crash file name, use --crash-file to specify"
     sys.exit(1)
   else:
     crashed_file = options.crash_file
 
   if not options.timeout_file:
-    print "missing timeout file, use --timeout-file to specify"
+    print "Missing timeout file, use --timeout-file to specify"
     sys.exit(1)
   else:
     timedout_file = options.timeout_file
 
-  http = RandomPick(HTTP_URL_FILE, 500000, NUM_URLS)
-  https = RandomPick(HTTPS_URL_FILE, 45000, NUM_URLS)
-
-  if generate_url:
-    file_handle = open(path, "w")
-    for i in range(0, NUM_URLS):
-      file_handle.write(http[i] + "\n")
-      file_handle.write(https[i] + "\n")
-    file_handle.close()
-
   adb_cmd = "adb "
   if options.adb_options:
     adb_cmd += options.adb_options + " "
@@ -128,6 +91,10 @@
     logging.error(adb_error)
     sys.exit(1)
 
+  # clean up previous results
+  RemoveDeviceFile(adb_cmd, TEST_STATUS_FILE)
+  RemoveDeviceFile(adb_cmd, TEST_TIMEOUT_FILE)
+
   logging.info("Running the test ...")
 
   # Count crashed tests.
@@ -142,11 +109,10 @@
 
   # Call ReliabilityTestsAutoTest#startReliabilityTests
   test_cmd = (test_cmd_prefix + " -e class "
-              "com.android.dumprendertree.ReliabilityTestsAutoTest#"
-              "startReliabilityTests -e timeout " + timeout_ms
-              + test_cmd_postfix)
+              "com.android.dumprendertree.ReliabilityTest#"
+              "runTest -e timeout %d %s" %
+              (timeout_ms, test_cmd_postfix))
 
-  time_start = time.time()
   adb_output = subprocess.Popen(test_cmd, shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE).communicate()[0]
@@ -160,16 +126,12 @@
     logging.info("Resuming reliability test runner...")
 
     test_cmd = (test_cmd_prefix + " -e class "
-                "com.android.dumprendertree.ReliabilityTestsAutoTest#"
-                "resumeReliabilityTests -e timeout " + timeout_ms
-                + test_cmd_postfix)
+                "com.android.dumprendertree.ReliabilityTest#"
+                "runTest -e timeout %d %s" %
+                (timeout_ms, test_cmd_postfix))
     adb_output = subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE).communicate()[0]
 
-  time_end = time.time()
-  fp = open("time_stat", "a")
-  fp.writelines("%.2f\n" % ((time_end - time_start) / NUM_URLS / 2))
-  fp.close()
   if (adb_output.find("INSTRUMENTATION_FAILED") != -1 or
       adb_output.find("Process crashed.") != -1):
     logging.error("Error happened : " + adb_output)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
new file mode 100644
index 0000000..081ddafa
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -0,0 +1,171 @@
+package com.android.dumprendertree;
+
+import android.os.Handler;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class ReliabilityTest extends ActivityInstrumentationTestCase2<ReliabilityTestActivity> {
+    
+    private static final String LOGTAG = "ReliabilityTest";
+    private static final String PKG_NAME = "com.android.dumprendertree";
+    private static final String TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt";
+    private static final String TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt";
+    private static final String TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt";
+    private static final String TEST_DONE = "#DONE";
+    static final String RELIABILITY_TEST_RUNNER_FILES[] = {
+        "run_reliability_tests.py"
+    };
+
+    public ReliabilityTest() {
+        super(PKG_NAME, ReliabilityTestActivity.class);
+    }
+    
+    @Override
+    protected void runTest() throws Throwable {
+        ReliabilityTestActivity activity = getActivity();
+        LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner)getInstrumentation();
+        
+        File testListFile = new File(TEST_LIST_FILE);
+        if(!testListFile.exists())
+            throw new FileNotFoundException("test list file not found.");
+        
+        BufferedReader listReader = new BufferedReader(
+                new FileReader(testListFile));
+        
+        //always try to resume first, hence cleaning up status will be the
+        //responsibility of driver scripts
+        String lastUrl = readTestStatus();
+        if(lastUrl != null && !TEST_DONE.equals(lastUrl))
+            fastForward(listReader, lastUrl);
+        
+        String url = null;
+        Handler handler = null;
+        boolean timeoutFlag = false;
+        long start, elapsed;
+        //read from BufferedReader instead of populating a list in advance,
+        //this will avoid excessive memory usage in case of a large list
+        while((url = listReader.readLine()) != null) {
+            start = System.currentTimeMillis();
+            Log.v(LOGTAG, "Testing URL: " + url);
+            updateTestStatus(url);
+            activity.reset();
+            //use message to send new URL to avoid interacting with
+            //WebView in non-UI thread
+            handler = activity.getHandler();
+            handler.sendMessage(handler.obtainMessage(
+                    ReliabilityTestActivity.MSG_NAVIGATE, 
+                    runner.mTimeoutInMillis, 0, url));
+            timeoutFlag = activity.waitUntilDone();
+            elapsed = System.currentTimeMillis() - start;
+            if(elapsed < 1000) {
+                Log.w(LOGTAG, "Page load finished in " + elapsed
+                        + "ms, too soon?");
+            } else {
+                Log.v(LOGTAG, "Page load finished in " + elapsed + "ms");
+            }
+            if(timeoutFlag) {
+                writeTimeoutFile(url);
+            }
+            System.runFinalization();
+            System.gc();
+            System.gc();
+        }
+        updateTestStatus(TEST_DONE);
+        activity.finish();
+        listReader.close();
+    }
+    
+    public void copyRunnerAssetsToCache() {
+        try {
+            String out_dir = getActivity().getApplicationContext()
+            .getCacheDir().getPath() + "/";
+
+            for( int i=0; i< RELIABILITY_TEST_RUNNER_FILES.length; i++) {
+                InputStream in = getActivity().getAssets().open(
+                        RELIABILITY_TEST_RUNNER_FILES[i]);
+                OutputStream out = new FileOutputStream(
+                        out_dir + RELIABILITY_TEST_RUNNER_FILES[i]);
+
+                byte[] buf = new byte[2048];
+                int len;
+
+                while ((len = in.read(buf)) >= 0 ) {
+                    out.write(buf, 0, len);
+                }
+                out.close();
+                in.close();
+            }
+        }catch (IOException e) {
+            Log.e(LOGTAG, "Cannot extract scripts for testing.", e);
+        }
+    }
+    
+    private void updateTestStatus(String s) {
+        // write last tested url into status file
+        try {
+            BufferedOutputStream bos = new BufferedOutputStream(
+                    new FileOutputStream(TEST_STATUS_FILE));
+            bos.write(s.getBytes());
+            bos.close();
+        } catch (IOException e) {
+            Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE, e);
+        }
+    }
+    
+    private String readTestStatus() {
+        // read out the test name it stopped last time.
+        String status = null;
+        File testStatusFile = new File(TEST_STATUS_FILE);
+        if(testStatusFile.exists()) {
+            try {
+                BufferedReader inReader = new BufferedReader(
+                        new FileReader(testStatusFile));
+                status = inReader.readLine();
+                inReader.close();
+            } catch (IOException e) {
+                Log.e(LOGTAG, "Error reading test status.", e);
+            }
+        }
+        return status;
+    }
+    
+    private void fastForward(BufferedReader testListReader, String lastUrl) {
+        //fastforward the BufferedReader to the position right after last url
+        if(lastUrl == null)
+            return;
+        
+        String line = null;
+        try {
+            while((line = testListReader.readLine()) != null) {
+                if(lastUrl.equals(line))
+                    return;
+            }
+        } catch (IOException ioe) {
+            Log.e(LOGTAG, "Error while reading test list.", ioe);
+            return;
+        }
+    }
+
+    private void writeTimeoutFile(String s) {
+        //append to the file containing the list of timeout urls 
+        try {
+            BufferedOutputStream bos = new BufferedOutputStream(
+                    new FileOutputStream(TEST_TIMEOUT_FILE, true));
+            bos.write(s.getBytes());
+            bos.write('\n');
+            bos.close();
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Cannot update file " + TEST_TIMEOUT_FILE, e);
+        }
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
new file mode 100644
index 0000000..75f1400
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
@@ -0,0 +1,256 @@
+package com.android.dumprendertree;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Bitmap;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.webkit.HttpAuthHandler;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.webkit.WebSettings.LayoutAlgorithm;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+public class ReliabilityTestActivity extends Activity {
+    
+    public static final String TEST_URL_ACTION = "com.andrdoid.dumprendertree.TestUrlAction";
+    public static final String PARAM_URL = "URL";
+    public static final String PARAM_TIMEOUT = "Timeout";
+    public static final int RESULT_TIMEOUT = 0xDEAD;
+    public static final int MSG_TIMEOUT = 0xC001;
+    public static final int MSG_NAVIGATE = 0xC002;
+    
+    private static final String LOGTAG = "ReliabilityTestActivity";
+    
+    private WebView webView;
+    private SimpleWebViewClient webViewClient;
+    private SimpleChromeClient chromeClient;
+    private Handler handler;
+    private boolean timeoutFlag;
+    private boolean pageDone;
+    private Object pageDoneLock;
+    private int pageStartCount;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Log.v(LOGTAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
+        
+        LinearLayout contentView = new LinearLayout(this);
+        contentView.setOrientation(LinearLayout.VERTICAL);
+        setContentView(contentView);
+        setTitle("Idle");
+        
+        webView = new WebView(this);
+        webView.getSettings().setJavaScriptEnabled(true);
+        webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
+        webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
+        
+        webViewClient = new SimpleWebViewClient();
+        chromeClient = new SimpleChromeClient();
+        webView.setWebViewClient(webViewClient);
+        webView.setWebChromeClient(chromeClient);
+        
+        contentView.addView(webView, new LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+        
+        handler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_TIMEOUT:
+                        handleTimeout();
+                        return;
+                    case MSG_NAVIGATE:
+                        navigate((String)msg.obj, msg.arg1);
+                        return;
+                }
+            }
+        };
+        
+        pageDoneLock = new Object();
+    }
+    
+    public void reset() {
+        synchronized (pageDoneLock) {
+            pageDone = false;
+        }
+        timeoutFlag = false;
+        pageStartCount = 0;
+        chromeClient.resetJsTimeout();
+    }
+    
+    private void navigate(String url, int timeout) {
+        if(url == null) {
+            Log.v(LOGTAG, "URL is null, cancelling...");
+            finish();
+        }
+        webView.stopLoading();
+        Log.v(LOGTAG, "Navigating to URL: " + url);
+        webView.loadUrl(url);
+        
+        if(timeout != 0) {
+            //set a timer with specified timeout (in ms)
+            handler.sendMessageDelayed(handler.obtainMessage(MSG_TIMEOUT),
+                    timeout);
+        }
+    }
+    
+    @Override
+    protected void onDestroy() {
+        Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+        super.onDestroy();
+    }
+    
+    private boolean isPageDone() {
+        synchronized (pageDoneLock) {
+            return pageDone;
+        }
+    }
+    
+    private void setPageDone(boolean pageDone) {
+        synchronized (pageDoneLock) {
+            this.pageDone = pageDone;
+            pageDoneLock.notifyAll();
+        }
+    }
+    
+    private void handleTimeout() {
+        int progress = webView.getProgress();
+        webView.stopLoading();
+        Log.v(LOGTAG, "Page timeout triggered, progress = " + progress);
+        timeoutFlag = true;
+    }
+    
+    public boolean waitUntilDone() {
+        validateNotAppThread();
+        synchronized (pageDoneLock) {
+            while(!isPageDone()) {
+                try {
+                    pageDoneLock.wait();
+                } catch (InterruptedException ie) {
+                    //no-op
+                }
+            }
+        }
+        return timeoutFlag;
+    }
+    
+    public Handler getHandler() {
+        return handler;
+    }
+    
+    private final void validateNotAppThread() {
+        if (ActivityThread.currentActivityThread() != null) {
+            throw new RuntimeException(
+                "This method can not be called from the main application thread");
+        }
+    }
+
+    class SimpleWebViewClient extends WebViewClient {
+        
+        @Override
+        public void onReceivedError(WebView view, int errorCode, String description,
+                String failingUrl) {
+            Log.v(LOGTAG, "Received WebCore error: code=" + errorCode
+                    + ", description=" + description
+                    + ", url=" + failingUrl);
+        }
+        
+        @Override
+        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+            //ignore certificate error
+            Log.v(LOGTAG, "Received SSL error: " + error.toString());
+            handler.proceed();
+        }
+        
+        @Override
+        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,
+                String realm) {
+            //cancel http auth request
+            handler.cancel();
+        }
+        
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            pageStartCount++;
+            Log.v(LOGTAG, "onPageStarted: " + url);
+        }
+        
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            Log.v(LOGTAG, "onPageFinished: " + url);
+            handler.postDelayed(new WebViewStatusChecker(), 500);
+        }
+    }
+    
+    class SimpleChromeClient extends WebChromeClient {
+        
+        private int timeoutCounter = 0;
+        
+        @Override
+        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
+            result.confirm();
+            return true;
+        }
+        
+        @Override
+        public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
+            result.confirm();
+            return true;
+        }
+        
+        @Override
+        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
+                JsPromptResult result) {
+            result.confirm();
+            return true;
+        }
+        
+        @Override
+        public boolean onJsTimeout() {
+            timeoutCounter++;
+            Log.v(LOGTAG, "JavaScript timeout, count=" + timeoutCounter);
+            return timeoutCounter > 2;
+        }
+        
+        public void resetJsTimeout() {
+            timeoutCounter = 0;
+        }
+        
+        @Override
+        public void onReceivedTitle(WebView view, String title) {
+            ReliabilityTestActivity.this.setTitle(title);
+        }
+    }
+    
+    class WebViewStatusChecker implements Runnable {
+        
+        private int initialStartCount;
+        
+        public WebViewStatusChecker() {
+            initialStartCount = pageStartCount;
+        }
+        
+        public void run() {
+            if (initialStartCount == pageStartCount) {
+                //perform cleanup
+                webView.stopLoading();
+                Log.v(LOGTAG, "Finishing URL: " + webView.getUrl());
+                handler.removeMessages(MSG_TIMEOUT);
+                setPageDone(true);
+            }
+        }
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java
deleted file mode 100644
index 347efde..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package com.android.dumprendertree;
-
-import com.android.dumprendertree.TestShellActivity.DumpDataType;
-
-import android.content.Intent;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Vector;
-
-public class ReliabilityTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
-
-    private static final String LOGTAG = "ReliabilityTests";
-    private static final String TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt";
-    private static final String TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt";
-    private static final String TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt";
-    static final String RELIABILITY_TEST_RUNNER_FILES[] = {
-        "run_reliability_tests.py"
-    };
-
-    private boolean finished;
-    private List<String> testList; 
-
-    public ReliabilityTestsAutoTest() {
-        super("com.android.dumprendertree", TestShellActivity.class);
-    }
-
-    private void getTestList() {
-        // Read test list.
-        testList = new Vector<String>();
-        try {
-            BufferedReader inReader = new BufferedReader(new FileReader(TEST_LIST_FILE));
-            String line;
-            while ((line = inReader.readLine()) != null) {
-                testList.add(line);
-            }
-            inReader.close();
-            Log.v(LOGTAG, "Test list has " + testList.size() + " test(s).");
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
-        }
-    }
-
-    private void resumeTestList() {
-        // read out the test name it stopped last time.
-        try {
-            BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
-            String line = inReader.readLine();
-            for (int i = 0; i < testList.size(); i++) {
-                if (testList.get(i).equals(line)) {
-                    testList = new Vector<String>(testList.subList(i+1, testList.size()));
-                    break;
-                }
-            }
-            inReader.close();
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
-        }
-    }
-
-    private void clearTestStatus() {
-        // Delete TEST_STATUS_FILE
-        try {
-            File f = new File(TEST_STATUS_FILE);
-            if (f.delete())
-                Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
-            else
-                Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
-        }
-    }
-
-    private void clearTestTimeout() {
-        // Delete TEST_TIMEOUT_FILE
-        try {
-            File f = new File(TEST_TIMEOUT_FILE);
-            if (f.delete())
-                Log.v(LOGTAG, "Deleted " + TEST_TIMEOUT_FILE);
-            else
-                Log.e(LOGTAG, "Fail to delete " + TEST_TIMEOUT_FILE);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Fail to delete " + TEST_TIMEOUT_FILE + " : " + e.getMessage());
-        }
-    }
-
-    private void updateTestStatus(String s) {
-        // Write TEST_STATUS_FILE
-        try {
-            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
-            bos.write(s.getBytes());
-            bos.close();
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
-        }
-    }
-
-    private void writeTimeoutFile(String s) {
-        // Write TEST_TIMEOUT_FILE
-        try {
-            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_TIMEOUT_FILE, true));
-            bos.write(s.getBytes());
-            bos.write('\n');
-            bos.close();
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Cannot update file " + TEST_TIMEOUT_FILE);
-        }
-    }
-
-    private void runReliabilityTest(boolean resume) {
-        LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
-
-        getTestList();
-        if(!resume)
-            clearTestStatus();
-        else
-            resumeTestList();
-
-        TestShellActivity activity = getActivity();
-        activity.setDefaultDumpDataType(DumpDataType.NO_OP);
-        // Run tests.
-        for (int i = 0; i < testList.size(); i++) {
-            String s = testList.get(i);
-            updateTestStatus(s);
-            // Run tests
-            runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis);
-        }
-
-        updateTestStatus("#DONE");
-
-        activity.finish();
-    }
-
-    private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) {
-        activity.setCallback(new TestShellCallback() {
-            public void finished() {
-                synchronized (ReliabilityTestsAutoTest.this) {
-                    finished = true;
-                    ReliabilityTestsAutoTest.this.notifyAll();
-                }
-            }
-
-            public void timedOut(String url) {
-                writeTimeoutFile(url);
-            }
-        });
-
-        finished = false;
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setClass(activity, TestShellActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, url);
-        intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
-        activity.startActivity(intent);
-
-        // Wait until done.
-        synchronized (this) {
-            while(!finished){
-                try {
-                    this.wait();
-                } catch (InterruptedException e) { }
-            }
-        }
-    }
-
-    public void startReliabilityTests() {
-        clearTestTimeout();
-        runReliabilityTest(false);
-    }
-
-    public void resumeReliabilityTests() {
-        runReliabilityTest(true);
-    }
-
-    public void copyRunnerAssetsToCache() {
-        try {
-            String out_dir = getActivity().getApplicationContext()
-            .getCacheDir().getPath() + "/";
-
-            for( int i=0; i< RELIABILITY_TEST_RUNNER_FILES.length; i++) {
-                InputStream in = getActivity().getAssets().open(
-                        RELIABILITY_TEST_RUNNER_FILES[i]);
-                OutputStream out = new FileOutputStream(
-                        out_dir + RELIABILITY_TEST_RUNNER_FILES[i]);
-
-                byte[] buf = new byte[2048];
-                int len;
-
-                while ((len = in.read(buf)) >= 0 ) {
-                    out.write(buf, 0, len);
-                }
-                out.close();
-                in.close();
-            }
-        }catch (IOException e) {
-            e.printStackTrace();
-        }
-
-    }
-}
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index eaeb5b7..3778742 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.backuptest">
-    <application>
+    <application android:backupAgent="BackupTestAgent">
         <activity android:name="BackupTestActivity" android:label="_BackupTest">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -8,10 +8,5 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <service android:name="BackupTestService">
-           <intent-filter>
-               <action android:name="android.backup.BackupService.SERVICE" />
-           </intent-filter>
-        </service>
     </application>
 </manifest>
diff --git a/tests/backup/src/com/android/backuptest/BackupTestService.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
similarity index 89%
rename from tests/backup/src/com/android/backuptest/BackupTestService.java
rename to tests/backup/src/com/android/backuptest/BackupTestAgent.java
index 00eb86e..11e520e 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestService.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
@@ -16,15 +16,15 @@
 
 package com.android.backuptest;
 
-import android.backup.BackupService;
+import android.app.BackupAgent;
 import android.backup.BackupDataOutput;
 import android.backup.FileBackupHelper;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
-public class BackupTestService extends BackupService
+public class BackupTestAgent extends BackupAgent
 {
-    static final String TAG = "BackupTestService";
+    static final String TAG = "BackupTestAgent";
 
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
diff --git a/tests/sketch/AndroidManifest.xml b/tests/sketch/AndroidManifest.xml
index fbf3a09b..b8a13f6 100755
--- a/tests/sketch/AndroidManifest.xml
+++ b/tests/sketch/AndroidManifest.xml
@@ -17,7 +17,7 @@
     package="com.android.gesture.example">
 
     <uses-permission android:name="android.permission.READ_CONTACTS" />
-    <uses-permission android:name="android.permission.WRITE_SDCARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <application android:icon="@drawable/icon" android:label="@string/app_name">
 
diff --git a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java
index 6767de6..7865a5c 100644
--- a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java
+++ b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java
@@ -33,6 +33,7 @@
 import android.gesture.GestureOverlayView;
 import android.gesture.LetterRecognizer;
 import android.gesture.Prediction;
+import android.gesture.LetterRecognizers;
 
 import java.util.ArrayList;
 
@@ -57,8 +58,8 @@
         setContentView(R.layout.overlaydemo);
 
         // create a letter recognizer
-        mRecognizer = LetterRecognizer.getLetterRecognizer(this,
-                LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE);
+        mRecognizer = LetterRecognizers.fromType(this,
+                LetterRecognizers.RECOGNIZER_LATIN_LOWERCASE);
         mOverlay = (GestureOverlayView) findViewById(R.id.overlay);
 
         // load the contact list
diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntry.java b/tests/sketch/src/com/android/gesture/example/GestureEntry.java
index 3f86ed4..8dbec99 100644
--- a/tests/sketch/src/com/android/gesture/example/GestureEntry.java
+++ b/tests/sketch/src/com/android/gesture/example/GestureEntry.java
@@ -36,9 +36,10 @@
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.gesture.Gesture;
 
-import android.gesture.GestureLibrary;
 import android.gesture.GestureOverlayView;
 import android.gesture.Prediction;
+import android.gesture.GestureLibraries;
+import android.gesture.GestureLibrary;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -61,7 +62,7 @@
 
     private Spinner mRecognitionResult;
 
-    private GestureLibrary mGestureLibrary;
+    private GestureLibrary mGestureStore;
 
     private boolean mChangedByRecognizer = false;
 
@@ -71,8 +72,8 @@
         setContentView(R.layout.demo);
 
         // init the gesture library
-        mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME);
-        mGestureLibrary.load();
+        mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME);
+        mGestureStore.load();
 
         // create the spinner for showing the recognition results
         // the spinner also allows a user to correct a prediction
@@ -82,7 +83,7 @@
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                 // correct the recognition result by adding the new example
                 if (!mChangedByRecognizer) {
-                    mGestureLibrary.addGesture(parent.getSelectedItem().toString(), mGesturePad
+                    mGestureStore.addGesture(parent.getSelectedItem().toString(), mGesturePad
                             .getGesture());
                 } else {
                     mChangedByRecognizer = false;
@@ -109,7 +110,7 @@
             public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
                 overlay.clear(false);
             }
-            
+
             public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
             }
         });
@@ -134,7 +135,7 @@
                                 .findViewById(R.id.gesturename_edit);
                         String text = edittext.getText().toString().trim();
                         if (text.length() > 0) {
-                            mGestureLibrary.addGesture(text, mGesturePad.getGesture());
+                            mGestureStore.addGesture(text, mGesturePad.getGesture());
                         }
                     }
                 }).setNegativeButton(R.string.newgesture_dialog_cancel,
@@ -173,14 +174,14 @@
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        mGestureLibrary.load();
+        mGestureStore.load();
         mGesturePad.clear(false);
     }
 
     @Override
     protected void onPause() {
         super.onPause();
-        mGestureLibrary.save();
+        mGestureStore.save();
     }
 
     @Override
@@ -195,12 +196,12 @@
         if (gesture != null) {
             outState.putParcelable(PARCEL_KEY, gesture);
         }
-        mGestureLibrary.save();
+        mGestureStore.save();
     }
 
     private void recognize(Gesture gesture) {
         mChangedByRecognizer = true;
-        ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture);
+        ArrayList<Prediction> predictions = mGestureStore.recognize(gesture);
         ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this,
                 android.R.layout.simple_spinner_item, predictions);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
diff --git a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java
index a561c96..f5bf683 100755
--- a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java
+++ b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java
@@ -28,8 +28,9 @@
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.gesture.Gesture;
 
-import android.gesture.GestureLibrary;
 import android.gesture.GestureOverlayView;
+import android.gesture.GestureLibraries;
+import android.gesture.GestureLibrary;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -45,7 +46,7 @@
 
     private Spinner mGestureCategory;
 
-    private GestureLibrary mGesureLibrary;
+    private GestureLibrary mGesureStore;
 
     private ArrayList<Gesture> mGestures;
 
@@ -59,15 +60,15 @@
 
             String name = (String) mGestureCategory.getSelectedItem();
             Gesture gesture = mGestures.get(mCurrentGestureIndex);
-            mGesureLibrary.removeGesture(name, gesture);
+            mGesureStore.removeGesture(name, gesture);
 
-            mGestures = mGesureLibrary.getGestures(name);
+            mGestures = mGesureStore.getGestures(name);
 
             if (mGestures == null) {
                 // delete the entire entry
                 mCurrentGestureIndex = 0;
                 ArrayList<String> list = new ArrayList<String>();
-                list.addAll(mGesureLibrary.getGestureEntries());
+                list.addAll(mGesureStore.getGestureEntries());
                 Collections.sort(list);
                 ArrayAdapter<String> adapter = new ArrayAdapter<String>(GestureLibViewer.this,
                         android.R.layout.simple_spinner_item, list);
@@ -83,7 +84,7 @@
             }
         }
     }
-    
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -94,19 +95,19 @@
         mGesturePad.setEnabled(false);
 
         // init the gesture library
-        mGesureLibrary = new GestureLibrary(GestureEntry.GESTURE_FILE_NAME);
-        mGesureLibrary.load();
+        mGesureStore = GestureLibraries.fromFile(GestureEntry.GESTURE_FILE_NAME);
+        mGesureStore.load();
 
         mGestureCategory = (Spinner) findViewById(R.id.spinner);
         ArrayList<String> list = new ArrayList<String>();
-        if (!mGesureLibrary.getGestureEntries().isEmpty()) {
-            list.addAll(mGesureLibrary.getGestureEntries());
+        if (!mGesureStore.getGestureEntries().isEmpty()) {
+            list.addAll(mGesureStore.getGestureEntries());
             Collections.sort(list);
             ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                     android.R.layout.simple_spinner_item, list);
             adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
             mGestureCategory.setAdapter(adapter);
-            mGestures = mGesureLibrary.getGestures(list.get(0));
+            mGestures = mGesureStore.getGestures(list.get(0));
             mCurrentGestureIndex = 0;
             Gesture gesture = mGestures.get(mCurrentGestureIndex);
             mGesturePad.setGesture(gesture);
@@ -114,7 +115,7 @@
 
         mGestureCategory.setOnItemSelectedListener(new OnItemSelectedListener() {
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                mGestures = mGesureLibrary.getGestures((String) mGestureCategory.getSelectedItem());
+                mGestures = mGesureStore.getGestures((String) mGestureCategory.getSelectedItem());
                 if (!mGestures.isEmpty()) {
                     mCurrentGestureIndex = 0;
                     Gesture gesture = mGestures.get(mCurrentGestureIndex);
@@ -160,7 +161,7 @@
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
-            mGesureLibrary.save();
+            mGesureStore.save();
             setResult(RESULT_OK);
             finish();
             return true;
@@ -172,12 +173,12 @@
     @Override
     protected void onPause() {
         super.onPause();
-        mGesureLibrary.save();
+        mGesureStore.save();
     }
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        mGesureLibrary.save();
+        mGesureStore.save();
     }
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 7c3af69..3d65d3c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -72,8 +72,8 @@
 
     boolean isMulticastEnabled();
 
-    void enableMulticast(IBinder binder, String tag);
+    void acquireMulticastLock(IBinder binder, String tag);
 
-    void disableMulticast();
+    void releaseMulticastLock();
 }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1a7caef..5b8ced6 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -824,6 +824,117 @@
         return new WifiLock(WIFI_MODE_FULL, tag);
     }
 
+
+    /**
+     * Create a new MulticastLock
+     *
+     * @param tag a tag for the MulticastLock to identify it in debugging
+     *            messages.
+     *
+     * @return a new, unacquired MulticastLock with the given tag.
+     *
+     * @see MulticastLock
+     */
+    public MulticastLock createMulticastLock(String tag) {
+        return new MulticastLock(tag);
+    }
+
+    /**
+     * Allows an application to receive Wifi Multicast packets.
+     * Normally the Wifi stack filters out packets not explicitly
+     * addressed to this device.  Acquring a MulticastLock will
+     * cause the stack to receive packets addressed to multicast
+     * addresses.  Processing these extra packets can cause a noticable
+     * battery drain and should be disabled when not needed
+     */
+    public class MulticastLock {
+        private String mTag;
+        private final IBinder mBinder;
+        private boolean mHeld;
+
+        private MulticastLock(String tag) {
+            mTag = tag;
+            mBinder = new Binder();
+            mHeld = false;
+        }
+
+        /**
+         * Locks Wifi Multicast on until {@link #release} is called.
+         *
+         * The first call to {@code acquire} will lock the Multicast on
+         * but subsequent calls will be ignored.  Only one call to
+         * {@link #release} will be required, regardless of the number of
+         * times that {@code acquire} is called.
+         *
+         * Note that other applications may also lock Wifi Multicast on.
+         * Only they can relinquish their lock.
+         *
+         * Also note that applications cannot leave Multicast locked on.
+         * When an app exits or crashes, any Multicast locks will be released.
+         */
+        public void acquire() {
+            synchronized (mBinder) {
+                if (!mHeld) {
+                    try {
+                        mService.acquireMulticastLock(mBinder, mTag);
+                        mHeld = true;
+                    } catch (RemoteException ignore) {
+                    }
+                }
+            }
+        }
+
+        /**
+         * Unlocks Wifi Multicast, restoring the filter of packets
+         * not addressed specifically to this device and saving power.
+         *
+         * Note that if any other Wifi Multicast Locks are still outstanding
+         * this {@code release} call will not have an immediate effect.  Only
+         * when all applications have released all their Multicast Locks will
+         * the Multicast filter be turned back on.
+         *
+         * Also note that when an app exits or crashes all of its Multicast
+         * Locks will be automatically released.
+         */
+        public void release() {
+            synchronized (mBinder) {
+                if (mHeld) {
+                    try {
+                        mService.releaseMulticastLock();
+                        mHeld = false;
+                    } catch (RemoteException ignore) {
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks whether this MulticastLock is currently held.
+         *
+         * @return true if this MulticastLock is held, false otherwise
+         */
+        public boolean isHeld() {
+            synchronized (mBinder) {
+                return mHeld;
+            }
+        }
+
+        public String toString() {
+            String s1, s2;
+            synchronized (mBinder) {
+                s1 = Integer.toHexString(System.identityHashCode(this));
+                s2 = mHeld ? "held; " : "";
+                return "MulticastLock{ " + s1 + "; " + s2 + " }";
+            }
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            super.finalize();
+            release();
+        }
+    }
+
     /**
      * Check multicast filter status.
      *
@@ -838,50 +949,4 @@
             return false;
         }
     }
-
-    /**
-     * Turn on the reception of multicast packets.
-     * The default behavior is to disable multicast packets as they
-     * have a noticable negative effect on battery life.  An
-     * application can turn them on, but should not leave it on for longer
-     * than needed.  When the app quits (or crashes) its request will
-     * be reverted.
-     *
-     * @param tag a string associated with this request for debugging.
-     *
-     * @return true on success
-     *
-     * @see #disableMulticast
-     *
-     * @hide pending API council approval
-     */
-    public boolean enableMulticast(String tag) {
-        try {
-            mService.enableMulticast(new Binder(), tag);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Return to the default multicast-off setting.
-     * Note that if others had turned on Multicast reception, your
-     * call will not turn it back off - they must also turn off their
-     * request for multicast reception.
-     *
-     * @return true on success
-     *
-     * @see #enableMulticast
-     *
-     * @hide pending API council approval
-     */
-    public boolean disableMulticast() {
-        try {
-            mService.disableMulticast();
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
 }
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 6771136..2fbc779 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -747,8 +747,10 @@
                  * first and then off.. if nobody else wants it on it'll be
                  * off then and it's all synchronized within the API.
                  */
-                mWM.enableMulticast("WifiStateTracker");
-                mWM.disableMulticast();
+                WifiManager.MulticastLock l = 
+                        mWM.createMulticastLock("WifiStateTracker");
+                l.acquire();
+                l.release();
 
                 if (mBluetoothA2dp == null) {
                     mBluetoothA2dp = new BluetoothA2dp(mContext);