Merge change 2017 into donut

* changes:
  Increment BatteryStatsImpl's VERSION. That'll make it stop trying to interpret older records with the new format. Also applied other comments involving name changes to remove un-needed 'Wifi' labels in WifiManager API, etc.
diff --git a/api/current.xml b/api/current.xml
index b743b03..6fe382d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1035,6 +1035,17 @@
  visibility="public"
 >
 </field>
+<field name="STOP_APP_SWITCHES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.STOP_APP_SWITCHES&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SUBSCRIBED_FEEDS_READ"
  type="java.lang.String"
  transient="false"
@@ -1471,6 +1482,17 @@
  visibility="public"
 >
 </field>
+<field name="linear_interpolator"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432587"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="overshoot_interpolator"
  type="int"
  transient="false"
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 6d4b455..88ad265 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -194,18 +194,17 @@
         if (intent != null) {
             System.out.println("Starting: " + intent);
             try {
-                intent.addFlags(intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 // XXX should do something to determine the MIME type.
                 int res = mAm.startActivity(null, intent, intent.getType(),
                         null, 0, null, null, 0, false, mDebugOption);
                 switch (res) {
                     case IActivityManager.START_SUCCESS:
                         break;
-                    case IActivityManager.START_CLASS_NOT_FOUND:
-                        System.err.println("Error type 3");
-                        System.err.println("Error: Activity class " +
-                                intent.getComponent().toShortString()
-                                + " does not exist.");
+                    case IActivityManager.START_SWITCHES_CANCELED:
+                        System.err.println(
+                                "Warning: Activity not started because the "
+                                + " current activity is being kept for the user.");
                         break;
                     case IActivityManager.START_DELIVERED_TO_TOP:
                         System.err.println(
@@ -213,16 +212,6 @@
                                 + "been delivered to currently running "
                                 + "top-most instance.");
                         break;
-                    case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
-                        System.err.println(
-                                "Error: Activity not started, you requested to "
-                                + "both forward and receive its result");
-                        break;
-                    case IActivityManager.START_INTENT_NOT_RESOLVED:
-                        System.err.println(
-                                "Error: Activity not started, unable to "
-                                + "resolve " + intent.toString());
-                        break;
                     case IActivityManager.START_RETURN_INTENT_TO_CALLER:
                         System.err.println(
                                 "Warning: Activity not started because intent "
@@ -233,6 +222,27 @@
                                 "Warning: Activity not started, its current "
                                 + "task has been brought to the front");
                         break;
+                    case IActivityManager.START_INTENT_NOT_RESOLVED:
+                        System.err.println(
+                                "Error: Activity not started, unable to "
+                                + "resolve " + intent.toString());
+                        break;
+                    case IActivityManager.START_CLASS_NOT_FOUND:
+                        System.err.println("Error type 3");
+                        System.err.println("Error: Activity class " +
+                                intent.getComponent().toShortString()
+                                + " does not exist.");
+                        break;
+                    case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
+                        System.err.println(
+                                "Error: Activity not started, you requested to "
+                                + "both forward and receive its result");
+                        break;
+                    case IActivityManager.START_PERMISSION_DENIED:
+                        System.err.println(
+                                "Error: Activity not started, you do not "
+                                + "have permission to access it.");
+                        break;
                     default:
                         System.err.println(
                                 "Error: Activity not started, unknown error "
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 541f413..16f0a30 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -998,6 +998,20 @@
             return true;
         }
         
+        case STOP_APP_SWITCHES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            stopAppSwitches();
+            reply.writeNoException();
+            return true;
+        }
+        
+        case RESUME_APP_SWITCHES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            resumeAppSwitches();
+            reply.writeNoException();
+            return true;
+        }
+        
         case PEEK_SERVICE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             Intent service = Intent.CREATOR.createFromParcel(data);
@@ -2182,5 +2196,25 @@
         return res;
     }
     
+    public void stopAppSwitches() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(STOP_APP_SWITCHES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+    
+    public void resumeAppSwitches() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(RESUME_APP_SWITCHES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+    
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
new file mode 100644
index 0000000..72cbff4
--- /dev/null
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.Printer;
+
+/**
+ * Describes an application error.
+ *
+ * A report has a type, which is one of
+ * <ul>
+ * <li> {@link #TYPE_CRASH} application crash. Information about the crash
+ * is stored in {@link #crashInfo}.
+ * <li> {@link #TYPE_ANR} application not responding. Information about the
+ * ANR is stored in {@link #anrInfo}.
+ * <li> {@link #TYPE_NONE} uninitialized instance of {@link ApplicationErrorReport}.
+ * </ul>
+ *
+ * @hide
+ */
+
+public class ApplicationErrorReport implements Parcelable {
+    /**
+     * Uninitialized error report.
+     */
+    public static final int TYPE_NONE = 0;
+
+    /**
+     * An error report about an application crash.
+     */
+    public static final int TYPE_CRASH = 1;
+
+    /**
+     * An error report about an application that's not responding.
+     */
+    public static final int TYPE_ANR = 2;
+
+    /**
+     * Type of this report. Can be one of {@link #TYPE_NONE},
+     * {@link #TYPE_CRASH} or {@link #TYPE_ANR}.
+     */
+    public int type;
+
+    /**
+     * Package name of the application.
+     */
+    public String packageName;
+
+    /**
+     * Package name of the application which installed the application this
+     * report pertains to.
+     * This identifies which Market the application came from.
+     */
+    public String installerPackageName;
+
+    /**
+     * Process name of the application.
+     */
+    public String processName;
+
+    /**
+     * Time at which the error occurred.
+     */
+    public long time;
+
+    /**
+     * If this report is of type {@link #TYPE_CRASH}, contains an instance
+     * of CrashInfo describing the crash; otherwise null.
+     */
+    public CrashInfo crashInfo;
+
+    /**
+     * If this report is of type {@link #TYPE_ANR}, contains an instance
+     * of AnrInfo describing the ANR; otherwise null.
+     */
+    public AnrInfo anrInfo;
+
+    /**
+     * Create an uninitialized instance of {@link ApplicationErrorReport}.
+     */
+    public ApplicationErrorReport() {
+    }
+
+    /**
+     * Create an instance of {@link ApplicationErrorReport} initialized from
+     * a parcel.
+     */
+    ApplicationErrorReport(Parcel in) {
+        type = in.readInt();
+        packageName = in.readString();
+        installerPackageName = in.readString();
+        processName = in.readString();
+        time = in.readLong();
+
+        switch (type) {
+            case TYPE_CRASH:
+                crashInfo = new CrashInfo(in);
+                break;
+            case TYPE_ANR:
+                anrInfo = new AnrInfo(in);
+                break;
+        }
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(type);
+        dest.writeString(packageName);
+        dest.writeString(installerPackageName);
+        dest.writeString(processName);
+        dest.writeLong(time);
+
+        switch (type) {
+            case TYPE_CRASH:
+                crashInfo.writeToParcel(dest, flags);
+                break;
+            case TYPE_ANR:
+                anrInfo.writeToParcel(dest, flags);
+                break;
+        }
+    }
+
+    /**
+     * Describes an application crash.
+     */
+    public static class CrashInfo {
+        /**
+         * Class name of the exception that caused the crash.
+         */
+        public String exceptionClassName;
+
+        /**
+         * File which the exception was thrown from.
+         */
+        public String throwFileName;
+
+        /**
+         * Class which the exception was thrown from.
+         */
+        public String throwClassName;
+
+        /**
+         * Method which the exception was thrown from.
+         */
+        public String throwMethodName;
+
+        /**
+         * Stack trace.
+         */
+        public String stackTrace;
+
+        /**
+         * Create an uninitialized instance of CrashInfo.
+         */
+        public CrashInfo() {
+        }
+
+        /**
+         * Create an instance of CrashInfo initialized from a Parcel.
+         */
+        public CrashInfo(Parcel in) {
+            exceptionClassName = in.readString();
+            throwFileName = in.readString();
+            throwClassName = in.readString();
+            throwMethodName = in.readString();
+            stackTrace = in.readString();
+        }
+
+        /**
+         * Save a CrashInfo instance to a parcel.
+         */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(exceptionClassName);
+            dest.writeString(throwFileName);
+            dest.writeString(throwClassName);
+            dest.writeString(throwMethodName);
+            dest.writeString(stackTrace);
+        }
+
+        /**
+         * Dump a CrashInfo instance to a Printer.
+         */
+        public void dump(Printer pw, String prefix) {
+            pw.println(prefix + "exceptionClassName: " + exceptionClassName);
+            pw.println(prefix + "throwFileName: " + throwFileName);
+            pw.println(prefix + "throwClassName: " + throwClassName);
+            pw.println(prefix + "throwMethodName: " + throwMethodName);
+            pw.println(prefix + "stackTrace: " + stackTrace);
+        }
+    }
+
+    /**
+     * Describes an application not responding error.
+     */
+    public static class AnrInfo {
+        /**
+         * Activity name.
+         */
+        public String activity;
+
+        /**
+         * Description of the operation that timed out.
+         */
+        public String cause;
+
+        /**
+         * Additional info, including CPU stats.
+         */
+        public String info;
+
+        /**
+         * Create an uninitialized instance of AnrInfo.
+         */
+        public AnrInfo() {
+        }
+
+        /**
+         * Create an instance of AnrInfo initialized from a Parcel.
+         */
+        public AnrInfo(Parcel in) {
+            activity = in.readString();
+            cause = in.readString();
+            info = in.readString();
+        }
+
+        /**
+         * Save an AnrInfo instance to a parcel.
+         */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(activity);
+            dest.writeString(cause);
+            dest.writeString(info);
+        }
+
+        /**
+         * Dump an AnrInfo instance to a Printer.
+         */
+        public void dump(Printer pw, String prefix) {
+            pw.println(prefix + "activity: " + activity);
+            pw.println(prefix + "cause: " + cause);
+            pw.println(prefix + "info: " + info);
+        }
+    }
+
+    public static final Parcelable.Creator<ApplicationErrorReport> CREATOR
+            = new Parcelable.Creator<ApplicationErrorReport>() {
+        public ApplicationErrorReport createFromParcel(Parcel source) {
+            return new ApplicationErrorReport(source);
+        }
+
+        public ApplicationErrorReport[] newArray(int size) {
+            return new ApplicationErrorReport[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Dump the report to a Printer.
+     */
+    public void dump(Printer pw, String prefix) {
+        pw.println(prefix + "type: " + type);
+        pw.println(prefix + "packageName: " + packageName);
+        pw.println(prefix + "installerPackageName: " + installerPackageName);
+        pw.println(prefix + "processName: " + processName);
+        pw.println(prefix + "time: " + time);
+
+        switch (type) {
+            case TYPE_CRASH:
+                crashInfo.dump(pw, prefix);
+                break;
+            case TYPE_ANR:
+                anrInfo.dump(pw, prefix);
+                break;
+        }
+    }
+}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 56b29c1..d15a154 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -44,9 +44,30 @@
  * {@hide}
  */
 public interface IActivityManager extends IInterface {
+    /**
+     * Returned by startActivity() if the start request was canceled because
+     * app switches are temporarily canceled to ensure the user's last request
+     * (such as pressing home) is performed.
+     */
+    public static final int START_SWITCHES_CANCELED = 4;
+    /**
+     * Returned by startActivity() if an activity wasn't really started, but
+     * the given Intent was given to the existing top activity.
+     */
     public static final int START_DELIVERED_TO_TOP = 3;
+    /**
+     * Returned by startActivity() if an activity wasn't really started, but
+     * a task was simply brought to the foreground.
+     */
     public static final int START_TASK_TO_FRONT = 2;
+    /**
+     * Returned by startActivity() if the caller asked that the Intent not
+     * be executed if it is the recipient, and that is indeed the case.
+     */
     public static final int START_RETURN_INTENT_TO_CALLER = 1;
+    /**
+     * Activity was started successfully as normal.
+     */
     public static final int START_SUCCESS = 0;
     public static final int START_INTENT_NOT_RESOLVED = -1;
     public static final int START_CLASS_NOT_FOUND = -2;
@@ -225,6 +246,9 @@
     
     public boolean shutdown(int timeout) throws RemoteException;
     
+    public void stopAppSwitches() throws RemoteException;
+    public void resumeAppSwitches() throws RemoteException;
+    
     /*
      * Private non-Binder interfaces
      */
@@ -371,4 +395,6 @@
     int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84;
     int PROFILE_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+85;
     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;
 }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 30acef9..333c7cb 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -604,6 +604,20 @@
      */
     public static final native void setThreadGroup(int tid, int group)
             throws IllegalArgumentException, SecurityException;
+    /**
+     * Sets the scheduling group for a process and all child threads
+     * @hide
+     * @param pid The indentifier of the process to change.
+     * @param group The target group for this process.
+     * 
+     * @throws IllegalArgumentException Throws IllegalArgumentException if
+     * <var>tid</var> does not exist.
+     * @throws SecurityException Throws SecurityException if your process does
+     * not have permission to modify the given thread, or to use the given
+     * priority.
+     */
+    public static final native void setProcessGroup(int pid, int group)
+            throws IllegalArgumentException, SecurityException;
     
     /**
      * Set the priority of the calling thread, based on Linux priorities.  See
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2a47b42..56a0104 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -148,7 +148,7 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_WIFI_SETTINGS =
             "android.settings.WIFI_SETTINGS";
-    
+
     /**
      * Activity Action: Show settings to allow configuration of a static IP
      * address for Wi-Fi.
@@ -305,7 +305,7 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_QUICK_LAUNCH_SETTINGS =
             "android.settings.QUICK_LAUNCH_SETTINGS";
-    
+
     /**
      * Activity Action: Show settings to manage installed applications.
      * <p>
@@ -319,7 +319,7 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS =
             "android.settings.MANAGE_APPLICATIONS_SETTINGS";
-    
+
     /**
      * Activity Action: Show settings for system update functionality.
      * <p>
@@ -329,7 +329,7 @@
      * Input: Nothing.
      * <p>
      * Output: Nothing.
-     * 
+     *
      * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -349,7 +349,7 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SYNC_SETTINGS =
             "android.settings.SYNC_SETTINGS";
-    
+
     /**
      * Activity Action: Show settings for selecting the network operator.
      * <p>
@@ -404,7 +404,7 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MEMORY_CARD_SETTINGS =
             "android.settings.MEMORY_CARD_SETTINGS";
-    
+
     // End of Intent actions for Settings
 
     private static final String JID_RESOURCE_PREFIX = "android";
@@ -495,7 +495,7 @@
         public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
 
         private static volatile NameValueCache mNameValueCache = null;
-        
+
         private static final HashSet<String> MOVED_TO_SECURE;
         static {
             MOVED_TO_SECURE = new HashSet<String>(30);
@@ -901,12 +901,12 @@
          * plugged in.
          */
         public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1;
-        
+
         /**
          * Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep.
          */
         public static final int WIFI_SLEEP_POLICY_NEVER = 2;
-        
+
         /**
          * Whether to use static IP and other static network attributes.
          * <p>
@@ -1115,12 +1115,12 @@
          * Note: This is a one-off setting that will be removed in the future
          * when there is profile support. For this reason, it is kept hidden
          * from the public APIs.
-         * 
+         *
          * @hide
          */
-        public static final String NOTIFICATIONS_USE_RING_VOLUME = 
+        public static final String NOTIFICATIONS_USE_RING_VOLUME =
             "notifications_use_ring_volume";
-        
+
         /**
          * The mapping of stream type (integer) to its setting.
          */
@@ -1188,7 +1188,7 @@
          * feature converts two spaces to a "." and space.
          */
         public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
-        
+
         /**
          * Setting to showing password characters in text editors. 1 = On, 0 = Off
          */
@@ -1270,13 +1270,13 @@
          * boolean (1 or 0).
          */
         public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
-        
+
         /**
          * Whether the haptic feedback (long presses, ...) are enabled. The value is
          * boolean (1 or 0).
          */
         public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
-        
+
         // Settings moved to Settings.Secure
 
         /**
@@ -1321,7 +1321,7 @@
          */
         @Deprecated
         public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
-        
+
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED}
          * instead
@@ -1334,7 +1334,7 @@
          */
         @Deprecated
         public static final String LOGGING_ID = Secure.LOGGING_ID;
-        
+
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#NETWORK_PREFERENCE} instead
          */
@@ -1374,7 +1374,7 @@
          */
         @Deprecated
         public static final String USB_MASS_STORAGE_ENABLED = Secure.USB_MASS_STORAGE_ENABLED;
-        
+
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#USE_GOOGLE_MAIL} instead
          */
@@ -1412,7 +1412,7 @@
         @Deprecated
         public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
             Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
-        
+
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}
          * instead
@@ -1448,7 +1448,7 @@
         @Deprecated
         public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
                 Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS;
-        
+
         /**
          * @deprecated Use
          * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED} instead
@@ -1824,19 +1824,19 @@
          * Whether the device has been provisioned (0 = false, 1 = true)
          */
         public static final String DEVICE_PROVISIONED = "device_provisioned";
-    
+
         /**
          * List of input methods that are currently enabled.  This is a string
          * containing the IDs of all enabled input methods, each ID separated
          * by ':'.
          */
         public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
-    
+
         /**
          * Host name and port for a user-selected proxy.
          */
         public static final String HTTP_PROXY = "http_proxy";
-    
+
         /**
          * Whether the package installer should allow installation of apps downloaded from
          * sources other than the Android Market (vending machine).
@@ -1845,12 +1845,12 @@
          * 0 = only allow installing from the Android Market
          */
         public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-    
+
         /**
          * Comma-separated list of location providers that activities may access.
          */
         public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
-    
+
         /**
          * The Logging ID (a unique 64-bit value) as a hex string.
          * Used as a pseudonymous identifier for logging.
@@ -1872,19 +1872,19 @@
          * connectivity service should touch this.
          */
         public static final String NETWORK_PREFERENCE = "network_preference";
-    
-        /** 
+
+        /**
          */
         public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
-    
-        /** 
+
+        /**
          */
         public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
-    
-        /** 
+
+        /**
          */
         public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
-    
+
         /**
          * Settings classname to launch when Settings is clicked from All
          * Applications.  Needed because of user testing between the old
@@ -1892,18 +1892,18 @@
          */
         // TODO: 881807
         public static final String SETTINGS_CLASSNAME = "settings_classname";
-    
+
         /**
          * USB Mass Storage Enabled
          */
         public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
-    
+
         /**
          * If this setting is set (to anything), then all references
          * to Gmail on the device must change to Google Mail.
          */
         public static final String USE_GOOGLE_MAIL = "use_google_mail";
-    
+
         /**
          * If accessibility is enabled.
          */
@@ -1926,64 +1926,64 @@
          */
         public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                 "wifi_networks_available_notification_on";
-    
+
         /**
          * Delay (in seconds) before repeating the Wi-Fi networks available notification.
          * Connecting to a network will reset the timer.
          */
         public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
                 "wifi_networks_available_repeat_delay";
-    
+
         /**
          * The number of radio channels that are allowed in the local
          * 802.11 regulatory domain.
          * @hide
          */
         public static final String WIFI_NUM_ALLOWED_CHANNELS = "wifi_num_allowed_channels";
-    
+
         /**
          * When the number of open networks exceeds this number, the
          * least-recently-used excess networks will be removed.
          */
         public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
-    
+
         /**
          * Whether the Wi-Fi should be on.  Only the Wi-Fi service should touch this.
          */
         public static final String WIFI_ON = "wifi_on";
-    
+
         /**
          * The acceptable packet loss percentage (range 0 - 100) before trying
          * another AP on the same network.
          */
         public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE =
                 "wifi_watchdog_acceptable_packet_loss_percentage";
-    
+
         /**
          * The number of access points required for a network in order for the
          * watchdog to monitor it.
          */
         public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
-    
+
         /**
          * The delay between background checks.
          */
         public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
                 "wifi_watchdog_background_check_delay_ms";
-    
+
         /**
          * Whether the Wi-Fi watchdog is enabled for background checking even
          * after it thinks the user has connected to a good access point.
          */
         public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED =
                 "wifi_watchdog_background_check_enabled";
-    
+
         /**
          * The timeout for a background ping
          */
         public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS =
                 "wifi_watchdog_background_check_timeout_ms";
-    
+
         /**
          * The number of initial pings to perform that *may* be ignored if they
          * fail. Again, if these fail, they will *not* be used in packet loss
@@ -1992,7 +1992,7 @@
          */
         public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT =
             "wifi_watchdog_initial_ignored_ping_count";
-    
+
         /**
          * The maximum number of access points (per network) to attempt to test.
          * If this number is reached, the watchdog will no longer monitor the
@@ -2000,7 +2000,7 @@
          * networks containing multiple APs whose DNS does not respond to pings.
          */
         public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
-    
+
         /**
          * Whether the Wi-Fi watchdog is enabled.
          */
@@ -2015,24 +2015,24 @@
          * The number of pings to test if an access point is a good connection.
          */
         public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
-    
+
         /**
          * The delay between pings.
          */
         public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
-    
+
         /**
          * The timeout per ping.
          */
         public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
-    
+
         /**
          * The maximum number of times we will retry a connection to an access
          * point for which we have failed in acquiring an IP address from DHCP.
          * A value of N means that we will make N+1 connection attempts in all.
          */
         public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
-    
+
         /**
          * Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile
          * data connectivity to be established after a disconnect from Wi-Fi.
@@ -2062,21 +2062,14 @@
         public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode";
 
         /**
-         * represents current active phone class
-         * 1 = GSM-Phone, 0 = CDMA-Phone
-         * @hide
-         */
-        public static final String CURRENT_ACTIVE_PHONE = "current_active_phone";
-
-        /**
-         * The preferred network mode 7 = Global
-         *                            6 = EvDo only
-         *                            5 = CDMA w/o EvDo
-         *                            4 = CDMA / EvDo auto
-         *                            3 = GSM / WCDMA auto
-         *                            2 = WCDMA only
-         *                            1 = GSM only
-         *                            0 = GSM / WCDMA preferred
+         * The preferred network mode   7 = Global
+         *                              6 = EvDo only
+         *                              5 = CDMA w/o EvDo
+         *                              4 = CDMA / EvDo auto
+         *                              3 = GSM / WCDMA auto
+         *                              2 = WCDMA only
+         *                              1 = GSM only
+         *                              0 = GSM / WCDMA preferred
          * @hide
          */
         public static final String PREFERRED_NETWORK_MODE =
@@ -2142,7 +2135,7 @@
                         allowedProviders.startsWith(provider + ",") ||
                         allowedProviders.endsWith("," + provider));
             }
-            return false;           
+            return false;
         }
 
         /**
@@ -2166,7 +2159,7 @@
             putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider);
         }
     }
-    
+
     /**
      * Gservices settings, containing the network names for Google's
      * various services. This table holds simple name/addr pairs.
@@ -2294,7 +2287,7 @@
          * Event tags from the kernel event log to upload during checkin.
          */
         public static final String CHECKIN_EVENTS = "checkin_events";
-        
+
         /**
          * Event tags for list of services to upload during checkin.
          */
@@ -2984,7 +2977,7 @@
         public static final String BATTERY_DISCHARGE_DURATION_THRESHOLD =
                 "battery_discharge_duration_threshold";
         public static final String BATTERY_DISCHARGE_THRESHOLD = "battery_discharge_threshold";
-        
+
         /**
          * An email address that anr bugreports should be sent to.
          */
@@ -3128,7 +3121,7 @@
 
         /**
          * Add a new bookmark to the system.
-         * 
+         *
          * @param cr The ContentResolver to query.
          * @param intent The desired target of the bookmark.
          * @param title Bookmark title that is shown to the user; null if none
@@ -3193,7 +3186,7 @@
         /**
          * Return the title as it should be displayed to the user. This takes
          * care of localizing bookmarks that point to activities.
-         * 
+         *
          * @param context A context.
          * @param cursor A cursor pointing to the row whose title should be
          *        returned. The cursor must contain at least the {@link #TITLE}
@@ -3208,24 +3201,24 @@
                 throw new IllegalArgumentException(
                         "The cursor must contain the TITLE and INTENT columns.");
             }
-            
+
             String title = cursor.getString(titleColumn);
             if (!TextUtils.isEmpty(title)) {
                 return title;
             }
-            
+
             String intentUri = cursor.getString(intentColumn);
             if (TextUtils.isEmpty(intentUri)) {
                 return "";
             }
-            
+
             Intent intent;
             try {
                 intent = Intent.getIntent(intentUri);
             } catch (URISyntaxException e) {
                 return "";
             }
-            
+
             PackageManager packageManager = context.getPackageManager();
             ResolveInfo info = packageManager.resolveActivity(intent, 0);
             return info != null ? info.loadLabel(packageManager) : "";
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index 9586d56..62631d6 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -34,6 +35,8 @@
  */
 public class Searchables {
 
+    private static final String LOG_TAG = "Searchables";
+
     // static strings used for XML lookups, etc.
     // TODO how should these be documented for the developer, in a more structured way than 
     // the current long wordy javadoc in SearchManager.java ?
@@ -184,7 +187,6 @@
      * TODO: sort the list somehow?  UI choice.
      */
     public void buildSearchableList() {
-        
         // These will become the new values at the end of the method
         HashMap<ComponentName, SearchableInfo> newSearchablesMap 
                                 = new HashMap<ComponentName, SearchableInfo>();
@@ -223,6 +225,11 @@
         ComponentName globalSearchActivity = globalSearchIntent.resolveActivity(pm);
         SearchableInfo newDefaultSearchable = newSearchablesMap.get(globalSearchActivity);
 
+        if (newDefaultSearchable == null) {
+            Log.w(LOG_TAG, "No searchable info found for new default searchable activity "
+                    + globalSearchActivity);
+        }
+
         // Store a consistent set of new values
         synchronized (this) {
             mSearchablesMap = newSearchablesMap;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 219afec..4297be0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1329,9 +1329,13 @@
                 } else {
                     // We need to retain the last set padding, so just clear
                     // out all of the fields in the existing structure.
+                    if (dr.mDrawableLeft != null) dr.mDrawableLeft.setCallback(null);
                     dr.mDrawableLeft = null;
+                    if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
                     dr.mDrawableTop = null;
+                    if (dr.mDrawableRight != null) dr.mDrawableRight.setCallback(null);
                     dr.mDrawableRight = null;
+                    if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
                     dr.mDrawableBottom = null;
                     dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0;
                     dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0;
@@ -1344,19 +1348,32 @@
                 mDrawables = dr = new Drawables();
             }
 
+            if (dr.mDrawableLeft != left && dr.mDrawableLeft != null) {
+                dr.mDrawableLeft.setCallback(null);
+            }
             dr.mDrawableLeft = left;
+            if (dr.mDrawableTop != left && dr.mDrawableTop != null) {
+                dr.mDrawableTop.setCallback(null);
+            }
             dr.mDrawableTop = top;
+            if (dr.mDrawableRight != left && dr.mDrawableRight != null) {
+                dr.mDrawableRight.setCallback(null);
+            }
             dr.mDrawableRight = right;
+            if (dr.mDrawableBottom != left && dr.mDrawableBottom != null) {
+                dr.mDrawableBottom.setCallback(null);
+            }
             dr.mDrawableBottom = bottom;
 
             final Rect compoundRect = dr.mCompoundRect;
-            int[] state = null;
+            int[] state;
 
             state = getDrawableState();
 
             if (left != null) {
                 left.setState(state);
                 left.copyBounds(compoundRect);
+                left.setCallback(this);
                 dr.mDrawableSizeLeft = compoundRect.width();
                 dr.mDrawableHeightLeft = compoundRect.height();
             } else {
@@ -1366,6 +1383,7 @@
             if (right != null) {
                 right.setState(state);
                 right.copyBounds(compoundRect);
+                right.setCallback(this);
                 dr.mDrawableSizeRight = compoundRect.width();
                 dr.mDrawableHeightRight = compoundRect.height();
             } else {
@@ -1375,6 +1393,7 @@
             if (top != null) {
                 top.setState(state);
                 top.copyBounds(compoundRect);
+                top.setCallback(this);
                 dr.mDrawableSizeTop = compoundRect.height();
                 dr.mDrawableWidthTop = compoundRect.width();
             } else {
@@ -1384,6 +1403,7 @@
             if (bottom != null) {
                 bottom.setState(state);
                 bottom.copyBounds(compoundRect);
+                bottom.setCallback(this);
                 dr.mDrawableSizeBottom = compoundRect.height();
                 dr.mDrawableWidthBottom = compoundRect.width();
             } else {
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index 004b0e3..0858741 100644
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -176,7 +176,7 @@
 {
     int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
     if (result) {
-        return result;
+        return false;
     }
 
     return (sGpsInterface->start() == 0);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index d760feb..95c38dc 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -236,6 +236,36 @@
         signalExceptionForGroupError(env, clazz, errno);
 }
 
+void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp) 
+{
+    DIR *d;
+    FILE *fp;
+    char proc_path[255];
+    struct dirent *de;
+
+    if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
+        signalExceptionForGroupError(env, clazz, EINVAL);
+        return;
+    }
+
+    sprintf(proc_path, "/proc/%d/task", pid);
+    if (!(d = opendir(proc_path))) {
+        signalExceptionForGroupError(env, clazz, errno);
+        return;
+    }
+
+    while ((de = readdir(d))) {
+        if (de->d_name[0] == '.')
+            continue;
+        if (add_pid_to_cgroup(atoi(de->d_name), grp)) {
+            signalExceptionForGroupError(env, clazz, errno);
+            closedir(d);
+            return;
+        }
+    }
+    closedir(d);
+}
+
 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
                                               jint pid, jint pri)
 {
@@ -820,6 +850,7 @@
     {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
     {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
     {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
+    {"setProcessGroup",      "(II)V", (void*)android_os_Process_setProcessGroup},
     {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
     {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
     {"setUid", "(I)I", (void*)android_os_Process_setUid},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ca2db11..b5f3a0f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -803,14 +803,22 @@
         android:description="@string/permdesc_runSetActivityWatcher"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to watch and control how activities are
-         started globally in the system.  Only for is in debugging
-         (usually the monkey command). -->
+    <!-- Allows an application to call the activity manager shutdown() API
+         to put the higher-level system there into a shutdown state. -->
     <permission android:name="android.permission.SHUTDOWN"
         android:label="@string/permlab_shutdown"
         android:description="@string/permdesc_shutdown"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to tell the activity manager to temporarily
+         stop application switches, putting it into a special mode that
+         prevents applications from immediately switching away from some
+         critical UI such as the home screen. -->
+    <permission android:name="android.permission.STOP_APP_SWITCHES"
+        android:label="@string/permlab_stopAppSwitches"
+        android:description="@string/permdesc_stopAppSwitches"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to retrieve the current state of keys and
          switches.  This is only for use by the system.-->
     <permission android:name="android.permission.READ_INPUT_STATE"
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b5808ea..af9dbcd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1106,6 +1106,7 @@
    <public type="anim" name="overshoot_interpolator" id="0x010a0008" />
    <public type="anim" name="anticipate_overshoot_interpolator" id="0x010a0009" />
    <public type="anim" name="bounce_interpolator" id="0x010a000a" />
+   <public type="anim" name="linear_interpolator" id="0x010a000b" />
 
   <public type="drawable" name="stat_sys_vp_phone_call" id="0x0108022d" />
   <public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x0108022e" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 058a445..0f146e5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -473,6 +473,12 @@
         state.  Does not perform a complete shutdown.</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_stopAppSwitches">prevent app switches</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_stopAppSwitches">Prevents the user from switching to
+        another application.</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_runSetActivityWatcher">monitor and control all application launching</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_runSetActivityWatcher">Allows an application to
@@ -1751,6 +1757,8 @@
     <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string>
     <!-- Button allowing the user to close an application that is not responding. This will kill the application. -->
     <string name="force_close">Force close</string>
+    <!-- Button allowing the user to send a bug report for application which has encountered an error. -->
+    <string name="report">Report</string>
     <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. -->
     <string name="wait">Wait</string>
     <!-- Button allowing a developer to connect a debugger to an application that is not responding. -->
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index b6d5078c..16a4f2d 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -71,8 +71,8 @@
 }
 
 AudioStreamIn* A2dpAudioInterface::openInputStream(
-        int format, int channelCount, uint32_t sampleRate, status_t *status,
-        AudioSystem::audio_in_acoustics acoustics)
+        int inputSource, int format, int channelCount, uint32_t sampleRate,
+        status_t *status, AudioSystem::audio_in_acoustics acoustics)
 {
     if (status)
         *status = -1;
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 7901a8c..091e775 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -55,6 +55,7 @@
                                 status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
+                                int inputSource,
                                 int format,
                                 int channelCount,
                                 uint32_t sampleRate,
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 9a94102..b72c94e 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -78,9 +78,9 @@
     virtual status_t    setParameter(const char* key, const char* value)
                             {return mFinalInterface->setParameter(key, value);}
 
-    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status,
-                                            AudioSystem::audio_in_acoustics acoustics)
-                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status, acoustics);}
+    virtual AudioStreamIn* openInputStream(int inputSource, int format, int channelCount,
+            uint32_t sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
+        { return mFinalInterface->openInputStream(inputSource, format, channelCount, sampleRate, status, acoustics); }
 
     virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
 
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index b56221f..e4f4aad 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -2407,7 +2407,9 @@
                
                 LOGV("AudioRecordThread: loop starting");
                 if (mRecordTrack != 0) {
-                    input = mAudioHardware->openInputStream(mRecordTrack->format(), 
+                    input = mAudioHardware->openInputStream(
+                                    mRecordTrack->type(),
+                                    mRecordTrack->format(), 
                                     mRecordTrack->channelCount(), 
                                     mRecordTrack->sampleRate(), 
                                     &mStartStatus,
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index 62beada..a97c0bc 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -30,6 +30,7 @@
 #include <utils/String8.h>
 
 #include "AudioHardwareGeneric.h"
+#include <media/AudioRecord.h>
 
 namespace android {
 
@@ -93,9 +94,15 @@
 }
 
 AudioStreamIn* AudioHardwareGeneric::openInputStream(
-        int format, int channelCount, uint32_t sampleRate, status_t *status,
-        AudioSystem::audio_in_acoustics acoustics)
+        int inputSource, int format, int channelCount, uint32_t sampleRate,
+        status_t *status, AudioSystem::audio_in_acoustics acoustics)
 {
+    // check for valid input source
+    if ((inputSource != AudioRecord::DEFAULT_INPUT) &&
+            (inputSource != AudioRecord::MIC_INPUT)) {
+        return 0;
+    }
+
     AutoMutex lock(mLock);
 
     // only one input stream allowed
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index c949aa1..c89df87 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -112,6 +112,7 @@
             status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
+            int inputSource,
             int format,
             int channelCount,
             uint32_t sampleRate,
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index b13cb1c..c61e6e6 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -23,6 +23,7 @@
 #include <utils/String8.h>
 
 #include "AudioHardwareStub.h"
+#include <media/AudioRecord.h>
 
 namespace android {
 
@@ -56,9 +57,15 @@
 }
 
 AudioStreamIn* AudioHardwareStub::openInputStream(
-        int format, int channelCount, uint32_t sampleRate,
+        int inputSource, int format, int channelCount, uint32_t sampleRate,
         status_t *status, AudioSystem::audio_in_acoustics acoustics)
 {
+    // check for valid input source
+    if ((inputSource != AudioRecord::DEFAULT_INPUT) &&
+            (inputSource != AudioRecord::MIC_INPUT)) {
+        return 0;
+    }
+
     AudioStreamInStub* in = new AudioStreamInStub();
     status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
     if (status) {
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index d406424..bf63cc5 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -78,6 +78,7 @@
                                 status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
+                                int inputSource,
                                 int format,
                                 int channelCount,
                                 uint32_t sampleRate,
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index d0ff9ce..ac59799 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -19,6 +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" />
     <application>    
         <uses-library android:name="android.test.runner" />
         <activity android:label="@string/app_name"
diff --git a/media/tests/MediaFrameworkTest/res/raw/testmidi.mid b/media/tests/MediaFrameworkTest/res/raw/testmidi.mid
index df84e20..d4ead53 100644
--- a/media/tests/MediaFrameworkTest/res/raw/testmidi.mid
+++ b/media/tests/MediaFrameworkTest/res/raw/testmidi.mid
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3 b/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3
index 89c44b0..b7d69f8 100644
--- a/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3
+++ b/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 407b4b36..fd3a4ba 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -26,25 +26,24 @@
     //A directory to hold all kinds of media files
     public static final String MEDIA_SAMPLE_POOL = "/sdcard/media_api/samples/";
     //Audio files
-    public static final String MP3CBR = "/sdcard/media_api/music/MP3CBR.mp3";  
-    public static final String MP3VBR = "/sdcard/media_api/music/MP3VBR.mp3";
+    public static final String MP3CBR = "/sdcard/media_api/music/MP3_256kbps_2ch.mp3";
+    public static final String MP3VBR = "/sdcard/media_api/music/MP3_256kbps_2ch_VBR.mp3";
     public static final String SHORTMP3 = "/sdcard/media_api/music/SHORTMP3.mp3";
-    public static final String MIDI = "/sdcard/media_api/music/MIDI.mid";
+    public static final String MIDI = "/sdcard/media_api/music/ants.mid";
     public static final String WMA9 = "/sdcard/media_api/music/WMA9.wma";
     public static final String WMA10 = "/sdcard/media_api/music/WMA10.wma";
-    public static final String WAV = "/sdcard/media_api/music/complicated_wav.wav";
-    public static final String AMR = "/sdcard/media_api/music/AMRNB.amr";
-    public static final String OGG = "/sdcard/media_api/music/Mists_of_Time-4T.ogg";
-    public static final String OGGSHORT = "/sdcard/media_api/music/Skippy.ogg";
+    public static final String WAV = "/sdcard/media_api/music/rings_2ch.wav";
+    public static final String AMR = "/sdcard/media_api/music/test_amr_ietf.amr";
+    public static final String OGG = "/sdcard/media_api/music/Revelation.ogg";
   
-    public static final int MP3CBR_LENGTH = 231116;  
-    public static final int MP3VBR_LENGTH = 126407;
+    public static final int MP3CBR_LENGTH = 71000;
+    public static final int MP3VBR_LENGTH = 71000;
     public static final int SHORTMP3_LENGTH = 286;
-    public static final int MIDI_LENGTH = 210528;
+    public static final int MIDI_LENGTH = 17000;
     public static final int WMA9_LENGTH = 126559;
     public static final int WMA10_LENGTH = 126559;
-    public static final int AMR_LENGTH = 126540;
-    public static final int OGG_LENGTH = 40000;
+    public static final int AMR_LENGTH = 37000;
+    public static final int OGG_LENGTH = 4000;
     public static final int SEEK_TIME = 10000;
   
     public static final long PAUSE_WAIT_TIME = 3000;
@@ -61,29 +60,21 @@
     //public static final String VIDEO_RTSP3GP = "rtsp://193.159.241.21/sp/alizee05.3gp";
   
     //local video
-    public static final String VIDEO_MP4 = "/sdcard/media_api/video/gingerkids.MP4";
+    public static final String VIDEO_MP4 = "/sdcard/media_api/video/MPEG4_320_AAC_64.mp4";
     public static final String VIDEO_LONG_3GP = "/sdcard/media_api/video/radiohead.3gp";
     public static final String VIDEO_SHORT_3GP = "/sdcard/media_api/video/short.3gp";
     public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/media_api/video/border_large.3gp";
-    public static final String VIDEO_H263_AAC = "/sdcard/media_api/video/H263_AAC.3gp";
-    public static final String VIDEO_H263_AMR = "/sdcard/media_api/video/H263_AMR.3gp";
-    public static final String VIDEO_H264_AAC = "/sdcard/media_api/video/H264_AAC.3gp";
-    public static final String VIDEO_H264_AMR = "/sdcard/media_api/video/H264_AMR.3gp";   
+    public static final String VIDEO_H263_AAC = "/sdcard/media_api/video/H263_56_AAC_24.3gp";
+    public static final String VIDEO_H263_AMR = "/sdcard/media_api/video/H263_56_AMRNB_6.3gp";
+    public static final String VIDEO_H264_AAC = "/sdcard/media_api/video/H264_320_AAC_64.3gp";
+    public static final String VIDEO_H264_AMR = "/sdcard/media_api/video/H264_320_AMRNB_6.3gp";
     public static final String VIDEO_WMV = "/sdcard/media_api/video/bugs.wmv";
-    public static final String VIDEO_HIGHRES_H263 = "/sdcard/media_api/video/h263_qcif_30fps.3gp";
-    public static final String VIDEO_HIGHRES_MP4 = "/sdcard/media_api/video/mpeg4_qvga_24fps.3gp";
+    public static final String VIDEO_HIGHRES_H263 = "/sdcard/media_api/video/H263_500_AMRNB_12.3gp";
+    public static final String VIDEO_HIGHRES_MP4 = "/sdcard/media_api/video/H264_500_AAC_128.3gp";
     
     //ringtone
     public static final String ringtone = "/sdcard/media_api/ringtones/F1_NewVoicemail.mp3";
-  
-    //streaming mp3
-    public static final String STREAM_LARGE_MP3 = 
-      "http://wms.pv.com:7070/MediaDownloadContent/mp3/BuenaVista_04_Pueblo_Nuevo.mp3";
-    public static final String STREAM_SMALL_MP3 = 
-      "http://wms.pv.com:7070/MediaDownloadContent/mp3/ID3V2_TestFile.mp3"; 
-    public static final String STREAM_REGULAR_MP3 = 
-      "http://wms.pv.com:7070/MediaDownloadContent/mp3/ElectricCosmo.mp3";
-  
+
     //streaming mp3
     public static final String STREAM_MP3_1 = 
       "http://wms.pv.com:7070/MediaDownloadContent/mp3/chadthi_jawani_128kbps.mp3";
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index cbd44ab..0c0974c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -32,8 +32,13 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.io.FileOutputStream;
 import java.util.Random;
 /**
  * Junit / Instrumentation test case for the media player api
@@ -80,7 +85,9 @@
         try{
             mp.setDataSource(filePath);
             mp.prepare(); 
-        }catch (Exception e){}
+        }catch (Exception e){
+            Log.v(TAG, e.toString());
+        }
         int duration = mp.getDuration();
         Log.v(TAG, "Duration " + duration);
         mp.release();
@@ -529,7 +536,6 @@
 
             //Verify the thumbnail 
             Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath);
-
             outputWidth = outThumbnail.getWidth();
             outputHeight = outThumbnail.getHeight();
             goldenHeight = goldenBitmap.getHeight();
@@ -539,15 +545,18 @@
             if ((outputWidth != goldenWidth) || (outputHeight != goldenHeight))
                 return false;
 
-            //Check one line of pixel
-            int x = goldenHeight/2;
-            for (int j=0; j<goldenWidth; j++){
-                if (goldenBitmap.getPixel(x, j) != outThumbnail.getPixel(x, j)){
+            // Check half line of pixel
+            int x = goldenHeight / 2;
+            for (int j = 1; j < goldenWidth / 2; j++) {
+                if (goldenBitmap.getPixel(x, j) != outThumbnail.getPixel(x, j)) {
                     Log.v(TAG, "pixel = " + goldenBitmap.getPixel(x, j));
-                    return false;    
+                    return false;
                 }
-            }
-        }catch (Exception e){}
+           }
+        }catch (Exception e){
+            Log.v(TAG, e.toString());
+            return false;
+        }
         return true;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index 94c69a8..e01bd53 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -410,7 +410,7 @@
     //Play a mid file which the duration is around 210 seconds
     @LargeTest
     public void testMidiResources() throws Exception {
-      boolean midiResources = CodecTest.resourcesPlayback(MediaFrameworkTest.midiafd,180000);
+      boolean midiResources = CodecTest.resourcesPlayback(MediaFrameworkTest.midiafd,16000);
       assertTrue("Play midi from resources", midiResources);         
     }
     
@@ -422,7 +422,7 @@
     
     @MediumTest
     public void testPrepareAsyncReset() throws Exception {
-      boolean isReset = CodecTest.prepareAsyncReset(MediaNames.STREAM_LARGE_MP3);
+      boolean isReset = CodecTest.prepareAsyncReset(MediaNames.STREAM_MP3);
       assertTrue("PrepareAsync Reset", isReset);         
     }
     
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b9d567c..f6958ed 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -65,7 +65,7 @@
     private static final String TAG = "SettingsProvider";
     private static final String DATABASE_NAME = "settings.db";
     private static final int DATABASE_VERSION = 34;
-    
+
     private Context mContext;
 
     public DatabaseHelper(Context context) {
@@ -81,7 +81,7 @@
                 ");");
         db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
     }
-    
+
     @Override
     public void onCreate(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE system (" +
@@ -134,7 +134,7 @@
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
         Log.w(TAG, "Upgrading settings database from version " + oldVersion + " to "
                 + currentVersion);
-        
+
         int upgradeVersion = oldVersion;
 
         // Pattern for upgrade blocks:
@@ -143,7 +143,7 @@
         //        .. your upgrade logic..
         //        upgradeVersion = [the DATABASE_VERSION you set]
         //    }
-        
+
         if (upgradeVersion == 20) {
             /*
              * Version 21 is part of the volume control refresh. There is no
@@ -156,7 +156,7 @@
 
             upgradeVersion = 21;
         }
-        
+
         if (upgradeVersion < 22) {
             upgradeVersion = 22;
             // Upgrade the lock gesture storage location and format
@@ -186,7 +186,7 @@
             }
             upgradeVersion = 24;
         }
-        
+
         if (upgradeVersion == 24) {
             db.beginTransaction();
             try {
@@ -213,7 +213,7 @@
             }
             upgradeVersion = 26;
         }
-        
+
         if (upgradeVersion == 26) {
             // This introduces the new secure settings table.
             db.beginTransaction();
@@ -225,12 +225,12 @@
             }
             upgradeVersion = 27;
         }
-        
+
         if (upgradeVersion == 27) {
             // Copy settings values from 'system' to 'secure' and delete them from 'system'
             SQLiteStatement insertStmt = null;
             SQLiteStatement deleteStmt = null;
-            
+
             db.beginTransaction();
             try {
                 insertStmt =
@@ -271,11 +271,11 @@
                     Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS,
                     Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS,
                 };
-                
+
                 for (String setting : settingsToMove) {
                     insertStmt.bindString(1, setting);
                     insertStmt.execute();
-                    
+
                     deleteStmt.bindString(1, setting);
                     deleteStmt.execute();
                 }
@@ -291,7 +291,7 @@
             }
             upgradeVersion = 28;
         }
-        
+
         if (upgradeVersion == 28 || upgradeVersion == 29) {
             // Note: The upgrade to 28 was flawed since it didn't delete the old
             // setting first before inserting. Combining 28 and 29 with the
@@ -313,10 +313,10 @@
             } finally {
                 db.endTransaction();
             }
-            
+
             upgradeVersion = 30;
         }
-        
+
         if (upgradeVersion == 30) {
             /*
              * Upgrade 31 clears the title for all quick launch shortcuts so the
@@ -373,7 +373,7 @@
             }
             upgradeVersion = 33;
         }
-        
+
         if (upgradeVersion == 33) {
             // Set the default zoom controls to: tap-twice to bring up +/-
             db.beginTransaction();
@@ -405,7 +405,7 @@
     }
 
     private void upgradeLockPatternLocation(SQLiteDatabase db) {
-        Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'", 
+        Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'",
                 null, null, null, null);
         if (c.getCount() > 0) {
             c.moveToFirst();
@@ -414,7 +414,7 @@
                 // Convert lock pattern
                 try {
                     LockPatternUtils lpu = new LockPatternUtils(mContext.getContentResolver());
-                    List<LockPatternView.Cell> cellPattern = 
+                    List<LockPatternView.Cell> cellPattern =
                             LockPatternUtils.stringToPattern(lockPattern);
                     lpu.saveLockPattern(cellPattern);
                 } catch (IllegalArgumentException e) {
@@ -542,12 +542,12 @@
                 AudioManager.RINGER_MODE_NORMAL);
 
         loadVibrateSetting(db, false);
-        
+
         // By default, only the ring/notification and system streams are affected
         loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,
                 (1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_NOTIFICATION) |
                 (1 << AudioManager.STREAM_SYSTEM));
-        
+
         loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
                 ((1 << AudioManager.STREAM_MUSIC) |
                  (1 << AudioManager.STREAM_RING) |
@@ -561,7 +561,7 @@
         if (deleteOld) {
             db.execSQL("DELETE FROM system WHERE name='" + Settings.System.VIBRATE_ON + "'");
         }
-        
+
         SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
                 + " VALUES(?,?);");
 
@@ -576,79 +576,78 @@
 
     private void loadSettings(SQLiteDatabase db) {
         loadSystemSettings(db);
-        loadSecureSettings(db);   
+        loadSecureSettings(db);
     }
-    
+
     private void loadSystemSettings(SQLiteDatabase db) {
         SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
                 + " VALUES(?,?);");
-        
+
         Resources r = mContext.getResources();
-        loadSetting(stmt, Settings.Secure.CURRENT_ACTIVE_PHONE,
-                RILConstants.CDMA_PHONE);
+
         loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
                 R.bool.def_dim_screen);
-        loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN, 
+        loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
                 "1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
         loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                 R.integer.def_screen_off_timeout);
-        
+
         loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
                 R.bool.def_airplane_mode_on);
-        
+
         loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
                 R.string.def_airplane_mode_radios);
-        
+
         loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
                 R.bool.def_auto_time); // Sync time to NITZ
-        
+
         loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
                 R.integer.def_screen_brightness);
-        
+
         loadDefaultAnimationSettings(stmt);
 
         loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
                 R.bool.def_accelerometer_rotation);
-        
+
         // Default date format based on build
         loadSetting(stmt, Settings.System.DATE_FORMAT,
-                SystemProperties.get("ro.com.android.dateformat", 
+                SystemProperties.get("ro.com.android.dateformat",
                         "MM-dd-yyyy"));
         stmt.close();
     }
-    
+
     private void loadDefaultAnimationSettings(SQLiteStatement stmt) {
         loadFractionSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE,
                 R.fraction.def_window_animation_scale, 1);
         loadFractionSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE,
                 R.fraction.def_window_transition_scale, 1);
     }
-    
+
     private void loadSecureSettings(SQLiteDatabase db) {
         SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
                 + " VALUES(?,?);");
-        
+
         loadBooleanSetting(stmt, Settings.Secure.BLUETOOTH_ON,
                 R.bool.def_bluetooth_on);
-        
+
         // Data roaming default, based on build
-        loadSetting(stmt, Settings.Secure.DATA_ROAMING, 
+        loadSetting(stmt, Settings.Secure.DATA_ROAMING,
                 "true".equalsIgnoreCase(
-                        SystemProperties.get("ro.com.android.dataroaming", 
-                                "false")) ? 1 : 0);        
-        
+                        SystemProperties.get("ro.com.android.dataroaming",
+                                "false")) ? 1 : 0);
+
         loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
                 R.bool.def_install_non_market_apps);
-        
+
         loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                 R.string.def_location_providers_allowed);
-        
+
         loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
                 R.integer.def_network_preference);
-        
+
         loadBooleanSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED,
                 R.bool.def_usb_mass_storage_enabled);
-        
+
         loadBooleanSetting(stmt, Settings.Secure.WIFI_ON,
                 R.bool.def_wifi_on);
         loadBooleanSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
@@ -660,25 +659,26 @@
         }
 
         // Set the preferred network mode to 0 = Global, CDMA default
-        loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, 
+        int type = SystemProperties.getInt("ro.telephony.default_network",
                 RILConstants.PREFERRED_NETWORK_MODE);
+        loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type);
 
         // Enable or disable Cell Broadcast SMS
         loadSetting(stmt, Settings.Secure.CDMA_CELL_BROADCAST_SMS,
                 RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
 
         // Set the preferred cdma subscription to 0 = Subscription from RUIM, when available
-        loadSetting(stmt, Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, 
+        loadSetting(stmt, Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION,
                 RILConstants.PREFERRED_CDMA_SUBSCRIPTION);
 
         // Don't do this.  The SystemServer will initialize ADB_ENABLED from a
         // persistent system property instead.
         //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0);
-        
+
         // Allow mock locations default, based on build
-        loadSetting(stmt, Settings.Secure.ALLOW_MOCK_LOCATION, 
+        loadSetting(stmt, Settings.Secure.ALLOW_MOCK_LOCATION,
                 "1".equals(SystemProperties.get("ro.allow.mock.location")) ? 1 : 0);
-        
+
         stmt.close();
     }
 
@@ -687,24 +687,23 @@
         stmt.bindString(2, value.toString());
         stmt.execute();
     }
-    
+
     private void loadStringSetting(SQLiteStatement stmt, String key, int resid) {
         loadSetting(stmt, key, mContext.getResources().getString(resid));
     }
-    
+
     private void loadBooleanSetting(SQLiteStatement stmt, String key, int resid) {
         loadSetting(stmt, key,
                 mContext.getResources().getBoolean(resid) ? "1" : "0");
     }
-    
+
     private void loadIntegerSetting(SQLiteStatement stmt, String key, int resid) {
         loadSetting(stmt, key,
                 Integer.toString(mContext.getResources().getInteger(resid)));
     }
-    
+
     private void loadFractionSetting(SQLiteStatement stmt, String key, int resid, int base) {
         loadSetting(stmt, key,
                 Float.toString(mContext.getResources().getFraction(resid, base, base)));
     }
 }
-
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c4dbd32..f2959e3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.AlertDialog;
+import android.app.ApplicationErrorReport;
 import android.app.Dialog;
 import android.app.IActivityWatcher;
 import android.app.IApplicationThread;
@@ -41,6 +42,7 @@
 import android.app.Instrumentation;
 import android.app.PendingIntent;
 import android.app.ResultInfo;
+import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -78,10 +80,14 @@
 import android.os.SystemProperties;
 import android.provider.Checkin;
 import android.provider.Settings;
+import android.server.data.CrashData;
+import android.server.data.StackTraceElementData;
+import android.server.data.ThrowableData;
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.LogPrinter;
 import android.util.PrintWriterPrinter;
 import android.util.SparseArray;
 import android.view.Gravity;
@@ -92,10 +98,13 @@
 
 import dalvik.system.Zygote;
 
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.IllegalStateException;
 import java.lang.ref.WeakReference;
@@ -191,6 +200,10 @@
     // Maximum number of recent tasks that we can remember.
     static final int MAX_RECENT_TASKS = 20;
 
+    // Amount of time after a call to stopAppSwitches() during which we will
+    // prevent further untrusted switches from happening.
+    static final long APP_SWITCH_DELAY_TIME = 5*1000;
+    
     // How long until we reset a task when the user returns to it.  Currently
     // 30 minutes.
     static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
@@ -328,6 +341,21 @@
     final ArrayList mHistory = new ArrayList();
 
     /**
+     * Description of a request to start a new activity, which has been held
+     * due to app switches being disabled.
+     */
+    class PendingActivityLaunch {
+        HistoryRecord r;
+        HistoryRecord sourceRecord;
+        Uri[] grantedUriPermissions;
+        int grantedMode;
+        boolean onlyIfNeeded;
+    }
+    
+    final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
+            = new ArrayList<PendingActivityLaunch>();
+    
+    /**
      * List of all active broadcasts that are to be executed immediately
      * (without waiting for another broadcast to finish).  Currently this only
      * contains broadcasts to registered receivers, to avoid spinning up
@@ -705,6 +733,18 @@
     int mFactoryTest;
 
     /**
+     * The time at which we will allow normal application switches again,
+     * after a call to {@link #stopAppSwitches()}.
+     */
+    long mAppSwitchesAllowedTime;
+
+    /**
+     * This is set to true after the first switch after mAppSwitchesAllowedTime
+     * is set; any switches after that will clear the time.
+     */
+    boolean mDidAppSwitch;
+    
+    /**
      * Set while we are wanting to sleep, to prevent any
      * activities from being started/resumed.
      */
@@ -852,6 +892,7 @@
     static final int SERVICE_ERROR_MSG = 18;
     static final int RESUME_TOP_ACTIVITY_MSG = 19;
     static final int PROC_START_TIMEOUT_MSG = 20;
+    static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
 
     AlertDialog mUidAlert;
 
@@ -910,6 +951,8 @@
                     d.show();
                     proc.anrDialog = d;
                 }
+                
+                ensureScreenEnabled();
             } break;
             case SHOW_FACTORY_ERROR_MSG: {
                 Dialog d = new FactoryErrorDialog(
@@ -1041,6 +1084,11 @@
                     processStartTimedOutLocked(app);
                 }
             }
+            case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    doPendingActivityLaunchesLocked(true);
+                }
+            }
             }
         }
     };
@@ -1495,6 +1543,18 @@
         return null;
     }
 
+    private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
+        int i = mHistory.size()-1;
+        while (i >= 0) {
+            HistoryRecord r = (HistoryRecord)mHistory.get(i);
+            if (!r.finishing && !r.delayedResume && r != notTop) {
+                return r;
+            }
+            i--;
+        }
+        return null;
+    }
+
     /**
      * This is a simplified version of topRunningActivityLocked that provides a number of
      * optional skip-over modes.  It is intended for use with the ActivityWatcher hook only.
@@ -2245,6 +2305,8 @@
             return true;
         }
 
+        next.delayedResume = false;
+        
         // If the top activity is the resumed one, nothing to do.
         if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
             // Make sure we have executed any pending transitions, since there
@@ -2471,7 +2533,8 @@
         return true;
     }
 
-    private final void startActivityLocked(HistoryRecord r, boolean newTask) {
+    private final void startActivityLocked(HistoryRecord r, boolean newTask,
+            boolean doResume) {
         final int NH = mHistory.size();
 
         int addPos = -1;
@@ -2558,7 +2621,7 @@
                 if ((r.intent.getFlags()
                         &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                     resetTaskIfNeededLocked(r, r);
-                    doShow = topRunningActivityLocked(null) == r;
+                    doShow = topRunningNonDelayedActivityLocked(null) == r;
                 }
             }
             if (SHOW_APP_STARTING_ICON && doShow) {
@@ -2588,13 +2651,15 @@
             mWindowManager.validateAppTokens(mHistory);
         }
 
-        resumeTopActivityLocked(null);
+        if (doResume) {
+            resumeTopActivityLocked(null);
+        }
     }
 
     /**
      * Perform clear operation as requested by
-     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: assuming the top task on the
-     * stack is the one that the new activity is being launched in, look for
+     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
+     * stack to the given task, then look for
      * an instance of that activity in the stack and, if found, finish all
      * activities on top of it and return the instance.
      *
@@ -2602,9 +2667,21 @@
      * @return Returns the old activity that should be continue to be used,
      * or null if none was found.
      */
-    private final HistoryRecord performClearTopTaskLocked(int taskId,
+    private final HistoryRecord performClearTaskLocked(int taskId,
             HistoryRecord newR, boolean doClear) {
         int i = mHistory.size();
+        
+        // First find the requested task.
+        while (i > 0) {
+            i--;
+            HistoryRecord r = (HistoryRecord)mHistory.get(i);
+            if (r.task.taskId == taskId) {
+                i++;
+                break;
+            }
+        }
+        
+        // Now clear it.
         while (i > 0) {
             i--;
             HistoryRecord r = (HistoryRecord)mHistory.get(i);
@@ -2840,15 +2917,75 @@
                 intent, resolvedType, aInfo, mConfiguration,
                 resultRecord, resultWho, requestCode, componentSpecified);
 
-        HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
-                != 0 ? r : null;
-
+        if (mResumedActivity == null
+                || mResumedActivity.info.applicationInfo.uid != callingUid) {
+            if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
+                PendingActivityLaunch pal = new PendingActivityLaunch();
+                pal.r = r;
+                pal.sourceRecord = sourceRecord;
+                pal.grantedUriPermissions = grantedUriPermissions;
+                pal.grantedMode = grantedMode;
+                pal.onlyIfNeeded = onlyIfNeeded;
+                mPendingActivityLaunches.add(pal);
+                return START_SWITCHES_CANCELED;
+            }
+        }
+        
+        if (mDidAppSwitch) {
+            // This is the second allowed switch since we stopped switches,
+            // so now just generally allow switches.  Use case: user presses
+            // home (switches disabled, switch to home, mDidAppSwitch now true);
+            // user taps a home icon (coming from home so allowed, we hit here
+            // and now allow anyone to switch again).
+            mAppSwitchesAllowedTime = 0;
+        } else {
+            mDidAppSwitch = true;
+        }
+     
+        doPendingActivityLaunchesLocked(false);
+        
+        return startActivityUncheckedLocked(r, sourceRecord,
+                grantedUriPermissions, grantedMode, onlyIfNeeded, true);
+    }
+  
+    private final void doPendingActivityLaunchesLocked(boolean doResume) {
+        final int N = mPendingActivityLaunches.size();
+        if (N <= 0) {
+            return;
+        }
+        for (int i=0; i<N; i++) {
+            PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
+            startActivityUncheckedLocked(pal.r, pal.sourceRecord,
+                    pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
+                    doResume && i == (N-1));
+        }
+        mPendingActivityLaunches.clear();
+    }
+    
+    private final int startActivityUncheckedLocked(HistoryRecord r,
+            HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
+            int grantedMode, boolean onlyIfNeeded, boolean doResume) {
+        final Intent intent = r.intent;
+        final int callingUid = r.launchedFromUid;
+        
+        int launchFlags = intent.getFlags();
+        
         // We'll invoke onUserLeaving before onPause only if the launching
         // activity did not explicitly state that this is an automated launch.
         mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
         if (DEBUG_USER_LEAVING) Log.v(TAG,
                 "startActivity() => mUserLeaving=" + mUserLeaving);
         
+        // If the caller has asked not to resume at this point, we make note
+        // of this in the record so that we can skip it when trying to find
+        // the top running activity.
+        if (!doResume) {
+            r.delayedResume = true;
+        }
+        
+        HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
+                != 0 ? r : null;
+
         // If the onlyIfNeeded flag is set, then we can do this if the activity
         // being launched is the same as the one making the call...  or, as
         // a special case, if we do not know the caller then we count the
@@ -2856,7 +2993,7 @@
         if (onlyIfNeeded) {
             HistoryRecord checkedCaller = sourceRecord;
             if (checkedCaller == null) {
-                checkedCaller = topRunningActivityLocked(notTop);
+                checkedCaller = topRunningNonDelayedActivityLocked(notTop);
             }
             if (!checkedCaller.realActivity.equals(r.realActivity)) {
                 // Caller is not the same as launcher, so always needed.
@@ -2894,7 +3031,7 @@
             launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
         }
 
-        if (resultRecord != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             // For whatever reason this activity is being launched into a new
             // task...  yet the caller has requested a result back.  Well, that
             // is pretty messed up, so instead immediately send back a cancel
@@ -2902,10 +3039,9 @@
             // dependency on its originator.
             Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
             sendActivityResultLocked(-1,
-                resultRecord, resultWho, requestCode,
+                    r.resultTo, r.resultWho, r.requestCode,
                 Activity.RESULT_CANCELED, null);
             r.resultTo = null;
-            resultRecord = null;
         }
 
         boolean addingToTask = false;
@@ -2916,7 +3052,7 @@
             // If bring to front is requested, and no result is requested, and
             // we can find a task that was started with this same
             // component, then instead of launching bring that one to the front.
-            if (resultRecord == null) {
+            if (r.resultTo == null) {
                 // See if there is a task to bring to the front.  If this is
                 // a SINGLE_INSTANCE activity, there can be one and only one
                 // instance of it in the history, and it is always in its own
@@ -2938,7 +3074,7 @@
                     // to have the same behavior as if a new instance was
                     // being started, which means not bringing it to the front
                     // if the caller is not itself in the front.
-                    HistoryRecord curTop = topRunningActivityLocked(notTop);
+                    HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
                     if (curTop.task != taskTop.task) {
                         r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                         boolean callerAtFront = sourceRecord == null
@@ -2959,7 +3095,9 @@
                         // the client said not to do anything if that
                         // is the case, so this is it!  And for paranoia, make
                         // sure we have correctly resumed the top activity.
-                        resumeTopActivityLocked(null);
+                        if (doResume) {
+                            resumeTopActivityLocked(null);
+                        }
                         return START_RETURN_INTENT_TO_CALLER;
                     }
                     if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
@@ -2969,7 +3107,7 @@
                         // from the task up to the one being started.  In most
                         // cases this means we are resetting the task to its
                         // initial state.
-                        HistoryRecord top = performClearTopTaskLocked(
+                        HistoryRecord top = performClearTaskLocked(
                                 taskTop.task.taskId, r, true);
                         if (top != null) {
                             if (top.frontOfTask) {
@@ -3035,7 +3173,9 @@
                         // We didn't do anything...  but it was needed (a.k.a., client
                         // don't use that intent!)  And for paranoia, make
                         // sure we have correctly resumed the top activity.
-                        resumeTopActivityLocked(null);
+                        if (doResume) {
+                            resumeTopActivityLocked(null);
+                        }
                         return START_TASK_TO_FRONT;
                     }
                 }
@@ -3052,8 +3192,8 @@
             // If the activity being launched is the same as the one currently
             // at the top, then we need to check if it should only be launched
             // once.
-            HistoryRecord top = topRunningActivityLocked(notTop);
-            if (top != null && resultRecord == null) {
+            HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
+            if (top != null && r.resultTo == null) {
                 if (top.realActivity.equals(r.realActivity)) {
                     if (top.app != null && top.app.thread != null) {
                         if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
@@ -3062,7 +3202,9 @@
                             logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
                             // For paranoia, make sure we have correctly
                             // resumed the top activity.
-                            resumeTopActivityLocked(null);
+                            if (doResume) {
+                                resumeTopActivityLocked(null);
+                            }
                             if (onlyIfNeeded) {
                                 // We don't need to start a new activity, and
                                 // the client said not to do anything if that
@@ -3077,9 +3219,9 @@
             }
 
         } else {
-            if (resultRecord != null) {
+            if (r.resultTo != null) {
                 sendActivityResultLocked(-1,
-                    resultRecord, resultWho, requestCode,
+                        r.resultTo, r.resultWho, r.requestCode,
                     Activity.RESULT_CANCELED, null);
             }
             return START_CLASS_NOT_FOUND;
@@ -3088,7 +3230,7 @@
         boolean newTask = false;
 
         // Should this be considered a new task?
-        if (resultRecord == null && !addingToTask
+        if (r.resultTo == null && !addingToTask
                 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             // todo: should do better management of integers.
             mCurTask++;
@@ -3108,14 +3250,16 @@
                 // In this case, we are adding the activity to an existing
                 // task, but the caller has asked to clear that task if the
                 // activity is already running.
-                HistoryRecord top = performClearTopTaskLocked(
+                HistoryRecord top = performClearTaskLocked(
                         sourceRecord.task.taskId, r, true);
                 if (top != null) {
                     logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
                     deliverNewIntentLocked(top, r.intent);
                     // For paranoia, make sure we have correctly
                     // resumed the top activity.
-                    resumeTopActivityLocked(null);
+                    if (doResume) {
+                        resumeTopActivityLocked(null);
+                    }
                     return START_DELIVERED_TO_TOP;
                 }
             } else if (!addingToTask &&
@@ -3128,7 +3272,9 @@
                     HistoryRecord top = moveActivityToFrontLocked(where);
                     logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
                     deliverNewIntentLocked(top, r.intent);
-                    resumeTopActivityLocked(null);
+                    if (doResume) {
+                        resumeTopActivityLocked(null);
+                    }
                     return START_DELIVERED_TO_TOP;
                 }
             }
@@ -3157,7 +3303,7 @@
             EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
         }
         logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
-        startActivityLocked(r, newTask);
+        startActivityLocked(r, newTask, doResume);
         return START_SUCCESS;
     }
 
@@ -4911,6 +5057,20 @@
         }
     }
 
+    final void ensureScreenEnabled() {
+        boolean enableScreen;
+        synchronized (this) {
+            enableScreen = !mBooted;
+            mBooted = true;
+        }
+
+        if (enableScreen) {
+            EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
+                SystemClock.uptimeMillis());
+            enableScreenAfterBoot();
+        }
+    }
+    
     public final void activityPaused(IBinder token, Bundle icicle) {
         // Refuse possible leaked file descriptors
         if (icicle != null && icicle.hasFileDescriptors()) {
@@ -6251,6 +6411,10 @@
                 "moveTaskToFront()");
 
         synchronized(this) {
+            if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+                    Binder.getCallingUid(), "Task to front")) {
+                return;
+            }
             final long origId = Binder.clearCallingIdentity();
             try {
                 int N = mRecentTasks.size();
@@ -6335,6 +6499,12 @@
                 "moveTaskToBack()");
 
         synchronized(this) {
+            if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
+                if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+                        Binder.getCallingUid(), "Task to back")) {
+                    return;
+                }
+            }
             final long origId = Binder.clearCallingIdentity();
             moveTaskToBackLocked(task);
             Binder.restoreCallingIdentity(origId);
@@ -6438,6 +6608,10 @@
                 "moveTaskBackwards()");
 
         synchronized(this) {
+            if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+                    Binder.getCallingUid(), "Task backwards")) {
+                return;
+            }
             final long origId = Binder.clearCallingIdentity();
             moveTaskBackwardsLocked(task);
             Binder.restoreCallingIdentity(origId);
@@ -7179,6 +7353,55 @@
         }
     }
 
+    public void stopAppSwitches() {
+        if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission "
+                    + android.Manifest.permission.STOP_APP_SWITCHES);
+        }
+        
+        synchronized(this) {
+            mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+                    + APP_SWITCH_DELAY_TIME;
+            mDidAppSwitch = false;
+            mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
+            Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
+            mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
+        }
+    }
+    
+    public void resumeAppSwitches() {
+        if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission "
+                    + android.Manifest.permission.STOP_APP_SWITCHES);
+        }
+        
+        synchronized(this) {
+            // Note that we don't execute any pending app switches... we will
+            // let those wait until either the timeout, or the next start
+            // activity request.
+            mAppSwitchesAllowedTime = 0;
+        }
+    }
+    
+    boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
+            String name) {
+        if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
+            return true;
+        }
+            
+        final int perm = checkComponentPermission(
+                android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
+                callingUid, -1);
+        if (perm == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        
+        Log.w(TAG, name + " request from " + callingUid + " stopped");
+        return false;
+    }
+    
     public void setDebugApp(String packageName, boolean waitForDebugger,
             boolean persistent) {
         enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
@@ -7595,6 +7818,30 @@
         return handleAppCrashLocked(app);
     }
 
+    private ComponentName getErrorReportReceiver(ProcessRecord app) {
+        IPackageManager pm = ActivityThread.getPackageManager();
+        try {
+            // was an installer package name specified when this app was
+            // installed?
+            String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
+            if (installerPackageName == null) {
+                return null;
+            }
+
+            // is there an Activity in this package that handles ACTION_APP_ERROR?
+            Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+            ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
+            if (info == null || info.activityInfo == null) {
+                return null;
+            }
+
+            return new ComponentName(installerPackageName, info.activityInfo.name);
+        } catch (RemoteException e) {
+            // will return null and no error report will be delivered
+        }
+        return null;
+    }
+
     void makeAppNotRespondingLocked(ProcessRecord app,
             String tag, String shortMsg, String longMsg, byte[] crashData) {
         app.notResponding = true;
@@ -7713,6 +7960,7 @@
     }
 
     void startAppProblemLocked(ProcessRecord app) {
+        app.errorReportReceiver = getErrorReportReceiver(app);
         skipCurrentReceiverLocked(app);
     }
 
@@ -7745,7 +7993,6 @@
     public int handleApplicationError(IBinder app, int flags,
             String tag, String shortMsg, String longMsg, byte[] crashData) {
         AppErrorResult result = new AppErrorResult();
-
         ProcessRecord r = null;
         synchronized (this) {
             if (app != null) {
@@ -7834,16 +8081,96 @@
 
         int res = result.get();
 
+        Intent appErrorIntent = null;
         synchronized (this) {
             if (r != null) {
                 mProcessCrashTimes.put(r.info.processName, r.info.uid,
                         SystemClock.uptimeMillis());
             }
+            if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
+                appErrorIntent = createAppErrorIntentLocked(r);
+                res = AppErrorDialog.FORCE_QUIT;
+            }
+        }
+
+        if (appErrorIntent != null) {
+            try {
+                mContext.startActivity(appErrorIntent);
+            } catch (ActivityNotFoundException e) {
+                Log.w(TAG, "bug report receiver dissappeared", e);
+            }
         }
 
         return res;
     }
     
+    Intent createAppErrorIntentLocked(ProcessRecord r) {
+        ApplicationErrorReport report = createAppErrorReportLocked(r);
+        if (report == null) {
+            return null;
+        }
+        Intent result = new Intent(Intent.ACTION_APP_ERROR);
+        result.setComponent(r.errorReportReceiver);
+        result.putExtra(Intent.EXTRA_BUG_REPORT, report);
+        result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return result;
+    }
+
+    ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
+        if (r.errorReportReceiver == null) {
+            return null;
+        }
+
+        if (!r.crashing && !r.notResponding) {
+            return null;
+        }
+
+        try {
+            ApplicationErrorReport report = new ApplicationErrorReport();
+            report.packageName = r.info.packageName;
+            report.installerPackageName = r.errorReportReceiver.getPackageName();
+            report.processName = r.processName;
+
+            if (r.crashing) {
+                report.type = ApplicationErrorReport.TYPE_CRASH;
+                report.crashInfo = new ApplicationErrorReport.CrashInfo();
+
+                ByteArrayInputStream byteStream = new ByteArrayInputStream(
+                        r.crashingReport.crashData);
+                DataInputStream dataStream = new DataInputStream(byteStream);
+                CrashData crashData = new CrashData(dataStream);
+                ThrowableData throwData = crashData.getThrowableData();
+
+                report.time = crashData.getTime();
+                report.crashInfo.stackTrace = throwData.toString();
+
+                // extract the source of the exception, useful for report
+                // clustering
+                while (throwData.getCause() != null) {
+                    throwData = throwData.getCause();
+                }
+                StackTraceElementData trace = throwData.getStackTrace()[0];
+                report.crashInfo.exceptionClassName = throwData.getType();
+                report.crashInfo.throwFileName = trace.getFileName();
+                report.crashInfo.throwClassName = trace.getClassName();
+                report.crashInfo.throwMethodName = trace.getMethodName();
+            } else if (r.notResponding) {
+                report.type = ApplicationErrorReport.TYPE_ANR;
+                report.anrInfo = new ApplicationErrorReport.AnrInfo();
+
+                report.anrInfo.activity = r.notRespondingReport.tag;
+                report.anrInfo.cause = r.notRespondingReport.shortMsg;
+                report.anrInfo.info = r.notRespondingReport.longMsg;
+            }
+
+            return report;
+        } catch (IOException e) {
+            // we don't send it
+        }
+
+        return null;
+    }
+
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
         // assume our apps are happy - lazy create the list
         List<ActivityManager.ProcessErrorStateInfo> errList = null;
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 3fcfad0..33894d6 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -19,17 +19,22 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
 
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
+import android.util.Log;
 
 class AppErrorDialog extends BaseErrorDialog {
+    private final static String TAG = "AppErrorDialog";
+
     private final AppErrorResult mResult;
     private final ProcessRecord mProc;
 
     // Event 'what' codes
     static final int FORCE_QUIT = 0;
     static final int DEBUG = 1;
+    static final int FORCE_QUIT_AND_REPORT = 2;
 
     // 5-minute timeout, then we automatically dismiss the crash dialog
     static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
@@ -58,12 +63,22 @@
 
         setCancelable(false);
 
-        setButton(res.getText(com.android.internal.R.string.force_close),
-                    mHandler.obtainMessage(FORCE_QUIT));
+        setButton(DialogInterface.BUTTON_POSITIVE,
+                res.getText(com.android.internal.R.string.force_close),
+                mHandler.obtainMessage(FORCE_QUIT));
+
         if ((flags&1) != 0) {
-            setButton(res.getText(com.android.internal.R.string.debug),
+            setButton(DialogInterface.BUTTON_NEUTRAL,
+                    res.getText(com.android.internal.R.string.debug),
                     mHandler.obtainMessage(DEBUG));
         }
+
+        if (app.errorReportReceiver != null) {
+            setButton(DialogInterface.BUTTON_NEGATIVE,
+                    res.getText(com.android.internal.R.string.report),
+                    mHandler.obtainMessage(FORCE_QUIT_AND_REPORT));
+        }
+
         setTitle(res.getText(com.android.internal.R.string.aerr_title));
         getWindow().addFlags(FLAG_SYSTEM_ERROR);
         getWindow().setTitle("Application Error: " + app.info.processName);
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index 7390ed0..03c2a04 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -18,7 +18,10 @@
 
 import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
 
+import android.content.ActivityNotFoundException;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
@@ -26,6 +29,13 @@
 import android.util.Log;
 
 class AppNotRespondingDialog extends BaseErrorDialog {
+    private static final String TAG = "AppNotRespondingDialog";
+
+    // Event 'what' codes
+    static final int FORCE_CLOSE = 1;
+    static final int WAIT = 2;
+    static final int WAIT_AND_REPORT = 3;
+
     private final ActivityManagerService mService;
     private final ProcessRecord mProc;
     
@@ -67,10 +77,19 @@
                 ? res.getString(resid, name1.toString(), name2.toString())
                 : res.getString(resid, name1.toString()));
 
-        setButton(res.getText(com.android.internal.R.string.force_close),
-                mHandler.obtainMessage(1));
-        setButton2(res.getText(com.android.internal.R.string.wait),
-                mHandler.obtainMessage(2));
+        setButton(DialogInterface.BUTTON_POSITIVE,
+                res.getText(com.android.internal.R.string.force_close),
+                mHandler.obtainMessage(FORCE_CLOSE));
+        setButton(DialogInterface.BUTTON_NEUTRAL,
+                res.getText(com.android.internal.R.string.wait),
+                mHandler.obtainMessage(WAIT));
+
+        if (app.errorReportReceiver != null) {
+            setButton(DialogInterface.BUTTON_NEGATIVE,
+                    res.getText(com.android.internal.R.string.report),
+                    mHandler.obtainMessage(WAIT_AND_REPORT));
+        }
+
         setTitle(res.getText(com.android.internal.R.string.anr_title));
         getWindow().addFlags(FLAG_SYSTEM_ERROR);
         getWindow().setTitle("Application Not Responding: " + app.info.processName);
@@ -81,16 +100,23 @@
 
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
+            Intent appErrorIntent = null;
             switch (msg.what) {
-                case 1:
+                case FORCE_CLOSE:
                     // Kill the application.
                     mService.killAppAtUsersRequest(mProc,
                             AppNotRespondingDialog.this, true);
                     break;
-                case 2:
+                case WAIT_AND_REPORT:
+                case WAIT:
                     // Continue waiting for the application.
                     synchronized (mService) {
                         ProcessRecord app = mProc;
+
+                        if (msg.what == WAIT_AND_REPORT) {
+                            appErrorIntent = mService.createAppErrorIntentLocked(app);
+                        }
+
                         app.notResponding = false;
                         app.notRespondingReport = null;
                         if (app.anrDialog == AppNotRespondingDialog.this) {
@@ -99,6 +125,14 @@
                     }
                     break;
             }
+
+            if (appErrorIntent != null) {
+                try {
+                    getContext().startActivity(appErrorIntent);
+                } catch (ActivityNotFoundException e) {
+                    Log.w(TAG, "bug report receiver dissappeared", e);
+                }
+            }
         }
     };
 }
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 1488791..1789687 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -85,6 +85,7 @@
     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
     boolean haveState;      // have we gotten the last activity state?
     boolean stopped;        // is activity pause finished?
+    boolean delayedResume;  // not yet resumed because of stopped app switches?
     boolean finishing;      // activity in pending finish list?
     boolean configDestroy;  // need to destroy due to config change?
     int configChangeFlags;  // which config values have changed
@@ -146,6 +147,7 @@
                 pw.print(" icicle="); pw.println(icicle);
         pw.print(prefix); pw.print("state="); pw.print(state);
                 pw.print(" stopped="); pw.print(stopped);
+                pw.print(" delayedResume="); pw.print(delayedResume);
                 pw.print(" finishing="); pw.println(finishing);
         pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
                 pw.print(" inHistory="); pw.print(inHistory);
@@ -191,6 +193,7 @@
         launchFailed = false;
         haveState = false;
         stopped = false;
+        delayedResume = false;
         finishing = false;
         configDestroy = false;
         keysPaused = false;
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 68aebc3..419dadf 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -107,6 +107,10 @@
     ActivityManager.ProcessErrorStateInfo crashingReport;
     ActivityManager.ProcessErrorStateInfo notRespondingReport;
 
+    // Who will be notified of the error. This is usually an activity in the
+    // app that installed the package.
+    ComponentName errorReportReceiver;
+
     void dump(PrintWriter pw, String prefix) {
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
@@ -157,7 +161,14 @@
                     pw.print(" "); pw.print(crashDialog);
                     pw.print(" notResponding="); pw.print(notResponding);
                     pw.print(" " ); pw.print(anrDialog);
-                    pw.print(" bad="); pw.println(bad);
+                    pw.print(" bad="); pw.print(bad);
+
+                    // crashing or notResponding is always set before errorReportReceiver
+                    if (errorReportReceiver != null) {
+                        pw.print(" errorReportReceiver=");
+                        pw.print(errorReportReceiver.flattenToShortString());
+                    }
+                    pw.println();
         }
         if (activities.size() > 0) {
             pw.print(prefix); pw.print("activities="); pw.println(activities);
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 5336e27..48cbace 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 import com.android.internal.util.CharSequences;
 
+import android.app.ActivityManagerNative;
 import android.app.Dialog;
 import android.app.IStatusBar;
 import android.app.PendingIntent;
@@ -1254,6 +1255,14 @@
 
         public void onClick(View v) {
             try {
+                // The intent we are sending is for the application, which
+                // won't have permission to immediately start an activity after
+                // the user switches to home.  We know it is safe to do at this
+                // point, so make sure new activity switches are now allowed.
+                ActivityManagerNative.getDefault().resumeAppSwitches();
+            } catch (RemoteException e) {
+            }
+            try {
                 mIntent.send();
                 mNotificationCallbacks.onNotificationClick(mPkg, mId);
             } catch (PendingIntent.CanceledException e) {
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 1483522..7d600f0 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -62,13 +62,10 @@
      * @hide
      */
     public static CellLocation newFromBundle(Bundle bundle) {
-        // TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0))
-        //       instead of SystemProperties???
-
-        // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup
-        //      ITelephony have not been created
-        if (RILConstants.CDMA_PHONE == SystemProperties.getInt(
-                Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE)) {
+        // TelephonyManager.getDefault().getPhoneType() handles the case when
+        // ITelephony interface is not up yet.
+        int type = TelephonyManager.getDefault().getPhoneType();
+        if (type == RILConstants.CDMA_PHONE) {
             return new CdmaCellLocation(bundle);
         } else {
             return new GsmCellLocation(bundle);
@@ -85,13 +82,10 @@
      *
      */
     public static CellLocation getEmpty() {
-        // TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0))
-        //       instead of SystemProperties???
-
-        // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup
-        //      ITelephony have not been created
-        if (RILConstants.CDMA_PHONE == SystemProperties.getInt(
-                Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE)) {
+        // TelephonyManager.getDefault().getPhoneType() handles the case when
+        // ITelephony interface is not up yet.
+        int type = TelephonyManager.getDefault().getPhoneType();
+        if (type == RILConstants.CDMA_PHONE) {
             return new CdmaCellLocation();
         } else {
             return new GsmCellLocation();
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 3b7f4b5..e73de3c 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -20,6 +20,7 @@
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.EncodeException;
+import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
 
@@ -307,7 +308,8 @@
 
         if (PHONE_TYPE_CDMA == activePhone) {
             spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, message, statusReportRequested, header);
+                    destinationAddress, message, statusReportRequested,
+                    SmsHeader.fromByteArray(header));
         } else {
             spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
                     destinationAddress, message, statusReportRequested, header);
@@ -331,7 +333,7 @@
 
         if (PHONE_TYPE_CDMA == activePhone) {
             spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, message, statusReportRequested);
+                    destinationAddress, message, statusReportRequested, null);
         } else {
             spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
                     destinationAddress, message, statusReportRequested);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 49a7750..a79eb3a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,26 +16,24 @@
 
 package android.telephony;
 
-import com.android.internal.telephony.*;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.telephony.CellLocation;
 
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.TelephonyProperties;
 
+import java.util.List;
+
 /**
  * Provides access to information about the telephony services on
  * the device. Applications can use the methods in this class to
@@ -239,10 +237,10 @@
 
     /**
      * Returns the neighboring cell information of the device.
-     * 
+     *
      * @return List of NeighboringCellInfo or null if info unavailable.
-     * 
-     * <p>Requires Permission: 
+     *
+     * <p>Requires Permission:
      * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES}
      */
     public List<NeighboringCellInfo> getNeighboringCellInfo() {
@@ -251,24 +249,25 @@
        } catch (RemoteException ex) {
        }
        return null;
-       
+
     }
-    
+
     /**
      * No phone module
+     *
      */
     public static final int PHONE_TYPE_NONE = 0;
 
     /**
      * GSM phone
      */
-    public static final int PHONE_TYPE_GSM = 1;
+    public static final int PHONE_TYPE_GSM = RILConstants.GSM_PHONE;
 
     /**
      * CDMA phone
      * @hide
      */
-    public static final int PHONE_TYPE_CDMA = 2;
+    public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
 
     /**
      * Returns a constant indicating the device phone type.
@@ -279,16 +278,41 @@
      */
     public int getPhoneType() {
         try{
-            if(getITelephony().getActivePhoneType() == RILConstants.CDMA_PHONE) {
-                return PHONE_TYPE_CDMA;
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                if(telephony.getActivePhoneType() == RILConstants.CDMA_PHONE) {
+                    return PHONE_TYPE_CDMA;
+                } else {
+                    return PHONE_TYPE_GSM;
+                }
             } else {
-                return PHONE_TYPE_GSM;
+                // This can happen when the ITelephony interface is not up yet.
+                return getPhoneTypeFromProperty();
             }
-        }catch(RemoteException ex){
-            return PHONE_TYPE_NONE;
+        } catch(RemoteException ex){
+            // This shouldn't happen in the normal case, as a backup we
+            // read from the system property.
+            return getPhoneTypeFromProperty();
         }
     }
 
+
+    private int getPhoneTypeFromProperty() {
+        int type =
+            SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+                    getPhoneTypeFromNetworkType());
+        return type;
+    }
+
+    private int getPhoneTypeFromNetworkType() {
+        // When the system property CURRENT_ACTIVE_PHONE, has not been set,
+        // use the system property for default network type.
+        // This is a fail safe, and can only happen at first boot.
+        int mode = SystemProperties.getInt("ro.telephony.default_network", -1);
+        if (mode == -1)
+            return PHONE_TYPE_NONE;
+        return PhoneFactory.getPhoneType(mode);
+    }
     //
     //
     // Current Network
@@ -640,8 +664,10 @@
     /** Data connection activity: Currently both sending and receiving
      *  IP PPP traffic. */
     public static final int DATA_ACTIVITY_INOUT = DATA_ACTIVITY_IN | DATA_ACTIVITY_OUT;
-    /** Data connection is active, but physical link is down */
-    /** @hide */
+    /**
+     * Data connection is active, but physical link is down
+     * @hide
+     */
     public static final int DATA_ACTIVITY_DORMANT = 0x00000004;
 
     /**
diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java
index 0928ddf..84dfca0 100644
--- a/telephony/java/android/telephony/gsm/SmsMessage.java
+++ b/telephony/java/android/telephony/gsm/SmsMessage.java
@@ -21,6 +21,7 @@
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.EncodeException;
+import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
 
@@ -369,7 +370,8 @@
 
         if (PHONE_TYPE_CDMA == activePhone) {
             spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, message, statusReportRequested, header);
+                    destinationAddress, message, statusReportRequested,
+                    SmsHeader.fromByteArray(header));
         } else {
             spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
                     destinationAddress, message, statusReportRequested, header);
@@ -395,7 +397,7 @@
 
         if (PHONE_TYPE_CDMA == activePhone) {
             spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, message, statusReportRequested);
+                    destinationAddress, message, statusReportRequested, null);
         } else {
             spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
                     destinationAddress, message, statusReportRequested);
@@ -744,4 +746,3 @@
         }
     }
 }
-
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 8f4c69c..8e2941b 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -182,7 +182,7 @@
             return stringToGsm7BitPacked(data);
         }
 
-        int headerBits = header.length * 8;
+        int headerBits = (header.length + 1) * 8;
         int headerSeptets = headerBits / 7;
         headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
 
@@ -194,7 +194,8 @@
                 (headerSeptets*7), true);
 
         // Paste in the header
-        System.arraycopy(header, 0, ret, 1, header.length);
+        ret[1] = (byte)header.length;
+        System.arraycopy(header, 0, ret, 2, header.length);
         return ret;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index b5f2afe..4d0cf41 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -165,18 +165,18 @@
 
     // Used for preferred network type
     // Note NT_* substitute RILConstants.NETWORK_MODE_* above the Phone
-    static final int NT_MODE_WCDMA_PREF   = 0; /* GSM/WCDMA (WCDMA preferred) */
-    static final int NT_MODE_GSM_ONLY     = 1; /* GSM only */
-    static final int NT_MODE_WCDMA_ONLY   = 2; /* WCDMA only */
-    static final int NT_MODE_GSM_UMTS     = 3; /* GSM/WCDMA (auto mode, according to PRL)
-                                                  AVAILABLE Application Settings menu */
-    static final int NT_MODE_CDMA         = 4; /* CDMA and EvDo (auto mode, according to PRL)
-                                                  AVAILABLE Application Settings menu */
-    static final int NT_MODE_CDMA_NO_EVDO = 5; /* CDMA only */
-    static final int NT_MODE_EVDO_NO_CDMA = 6; /* EvDo only */
-    static final int NT_MODE_GLOBAL       = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according
-                                                  to PRL) AVAILABLE Application Settings menu */
-    static final int PREFERRED_NT_MODE    = NT_MODE_GLOBAL;
+    int NT_MODE_WCDMA_PREF   = RILConstants.NETWORK_MODE_WCDMA_PREF;
+    int NT_MODE_GSM_ONLY     = RILConstants.NETWORK_MODE_GSM_ONLY;
+    int NT_MODE_WCDMA_ONLY   = RILConstants.NETWORK_MODE_WCDMA_ONLY;
+    int NT_MODE_GSM_UMTS     = RILConstants.NETWORK_MODE_GSM_UMTS;
+
+    int NT_MODE_CDMA         = RILConstants.NETWORK_MODE_CDMA;
+
+    int NT_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
+    int NT_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
+    int NT_MODE_GLOBAL       = RILConstants.NETWORK_MODE_GLOBAL;
+
+    int PREFERRED_NT_MODE    = RILConstants.PREFERRED_NETWORK_MODE;
 
 
     // Used for CDMA roaming mode
diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java
index 3beb60a..a84f74e 100644
--- a/telephony/java/com/android/internal/telephony/PhoneFactory.java
+++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java
@@ -107,33 +107,49 @@
                 //reads the system properties and makes commandsinterface
                 sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
 
-                switch(networkMode) {
-                    case RILConstants.NETWORK_MODE_WCDMA_PREF:
-                    case RILConstants.NETWORK_MODE_GSM_ONLY:
-                    case RILConstants.NETWORK_MODE_WCDMA_ONLY:
-                    case RILConstants.NETWORK_MODE_GSM_UMTS:
-                        sProxyPhone = new PhoneProxy(new GSMPhone(context,
-                                sCommandsInterface, sPhoneNotifier));
-                        Log.i(LOG_TAG, "Creating GSMPhone");
-                        break;
-                    case RILConstants.NETWORK_MODE_CDMA:
-                    case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
-                    case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
-                        sProxyPhone = new PhoneProxy(new CDMAPhone(context,
-                                sCommandsInterface, sPhoneNotifier));
-                        Log.i(LOG_TAG, "Creating CDMAPhone");
-                        break;
-                    case RILConstants.NETWORK_MODE_GLOBAL:
-                    default:
-                        sProxyPhone = new PhoneProxy(new CDMAPhone(context,
-                                sCommandsInterface, sPhoneNotifier));
-                        Log.i(LOG_TAG, "Creating CDMAPhone");
+                int phoneType = getPhoneType(networkMode);
+                if (phoneType == RILConstants.GSM_PHONE) {
+                    sProxyPhone = new PhoneProxy(new GSMPhone(context,
+                            sCommandsInterface, sPhoneNotifier));
+                    Log.i(LOG_TAG, "Creating GSMPhone");
+                } else if (phoneType == RILConstants.CDMA_PHONE) {
+                    sProxyPhone = new PhoneProxy(new CDMAPhone(context,
+                            sCommandsInterface, sPhoneNotifier));
+                    Log.i(LOG_TAG, "Creating CDMAPhone");
                 }
+
                 sMadeDefaults = true;
             }
         }
     }
 
+    /*
+     * This function returns the type of the phone, depending
+     * on the network mode.
+     *
+     * @param network mode
+     * @return Phone Type
+     */
+    public static int getPhoneType(int networkMode) {
+        switch(networkMode) {
+        case RILConstants.NETWORK_MODE_CDMA:
+        case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
+        case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
+            return RILConstants.CDMA_PHONE;
+
+        case RILConstants.NETWORK_MODE_WCDMA_PREF:
+        case RILConstants.NETWORK_MODE_GSM_ONLY:
+        case RILConstants.NETWORK_MODE_WCDMA_ONLY:
+        case RILConstants.NETWORK_MODE_GSM_UMTS:
+            return RILConstants.GSM_PHONE;
+
+        case RILConstants.NETWORK_MODE_GLOBAL:
+            return RILConstants.CDMA_PHONE;
+        default:
+            return RILConstants.GSM_PHONE;
+        }
+    }
+
     public static Phone getDefaultPhone() {
         if (sLooper != Looper.myLooper()) {
             throw new RuntimeException(
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 04e33fe..070d233 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1857,7 +1857,7 @@
                  * and/or radio knowing.
                  */
                 if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
-                    setRadioPower(false, null);
+                setRadioPower(false, null);
             } else {
                 if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
                 setRadioState(newState);
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index f2bd361..d055c311 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -122,7 +122,7 @@
      * CONCATENATED_16_BIT_REFERENCE message set.  Should be
      * incremented for each set of concatenated messages.
      */
-    protected static int sConcatenatedRef;
+    private static int sConcatenatedRef;
 
     private SmsCounter mCounter;
 
@@ -132,6 +132,11 @@
     private static SmsMessageBase mSmsMessageBase;
     private SmsMessageBase.SubmitPduBase mSubmitPduBase;
 
+    protected static int getNextConcatenatedRef() {
+        sConcatenatedRef += 1;
+        return sConcatenatedRef;
+    }
+
     /**
      *  Implement the per-application based SMS control, which only allows
      *  a limit on the number of SMS/MMS messages an app can send in checking
@@ -419,12 +424,15 @@
     /**
      * If this is the last part send the parts out to the application, otherwise
      * the part is stored for later processing.
+     *
+     * NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null.
      */
-    protected void processMessagePart(SmsMessageBase sms, int referenceNumber,
-            int sequence, int count, int destinationPort) {
+    protected void processMessagePart(SmsMessageBase sms,
+            SmsHeader.ConcatRef concatRef, SmsHeader.PortAddrs portAddrs) {
+
         // Lookup all other related parts
         StringBuilder where = new StringBuilder("reference_number =");
-        where.append(referenceNumber);
+        where.append(concatRef.refNumber);
         where.append(" AND address = ?");
         String[] whereArgs = new String[] {sms.getOriginatingAddress()};
 
@@ -433,20 +441,19 @@
         try {
             cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null);
             int cursorCount = cursor.getCount();
-            if (cursorCount != count - 1) {
+            if (cursorCount != concatRef.msgCount - 1) {
                 // We don't have all the parts yet, store this one away
                 ContentValues values = new ContentValues();
                 values.put("date", new Long(sms.getTimestampMillis()));
                 values.put("pdu", HexDump.toHexString(sms.getPdu()));
                 values.put("address", sms.getOriginatingAddress());
-                values.put("reference_number", referenceNumber);
-                values.put("count", count);
-                values.put("sequence", sequence);
-                if (destinationPort != -1) {
-                    values.put("destination_port", destinationPort);
+                values.put("reference_number", concatRef.refNumber);
+                values.put("count", concatRef.msgCount);
+                values.put("sequence", concatRef.seqNumber);
+                if (portAddrs != null) {
+                    values.put("destination_port", portAddrs.destPort);
                 }
                 mResolver.insert(mRawUri, values);
-
                 return;
             }
 
@@ -454,7 +461,7 @@
             int pduColumn = cursor.getColumnIndex("pdu");
             int sequenceColumn = cursor.getColumnIndex("sequence");
 
-            pdus = new byte[count][];
+            pdus = new byte[concatRef.msgCount][];
             for (int i = 0; i < cursorCount; i++) {
                 cursor.moveToNext();
                 int cursorSequence = (int)cursor.getLong(sequenceColumn);
@@ -462,7 +469,7 @@
                         cursor.getString(pduColumn));
             }
             // This one isn't in the DB, so add it
-            pdus[sequence - 1] = sms.getPdu();
+            pdus[concatRef.seqNumber - 1] = sms.getPdu();
 
             // Remove the parts from the database
             mResolver.delete(mRawUri, where.toString(), whereArgs);
@@ -473,31 +480,34 @@
             if (cursor != null) cursor.close();
         }
 
+        /**
+         * TODO(cleanup): The following code has duplicated logic with
+         * the radio-specific dispatchMessage code, which is fragile,
+         * in addition to being redundant.  Instead, if this method
+         * maybe returned the reassembled message (or just contents),
+         * the following code (which is not really related to
+         * reconstruction) could be better consolidated.
+         */
+
         // Dispatch the PDUs to applications
-        switch (destinationPort) {
-        case SmsHeader.PORT_WAP_PUSH: {
-            // Build up the data stream
-            ByteArrayOutputStream output = new ByteArrayOutputStream();
-            for (int i = 0; i < count; i++) {
-                SmsMessage msg = SmsMessage.createFromPdu(pdus[i]);
-                byte[] data = msg.getUserData();
-                output.write(data, 0, data.length);
+        if (portAddrs != null) {
+            if (portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
+                // Build up the data stream
+                ByteArrayOutputStream output = new ByteArrayOutputStream();
+                for (int i = 0; i < concatRef.msgCount; i++) {
+                    SmsMessage msg = SmsMessage.createFromPdu(pdus[i]);
+                    byte[] data = msg.getUserData();
+                    output.write(data, 0, data.length);
+                }
+                // Handle the PUSH
+                mWapPush.dispatchWapPdu(output.toByteArray());
+            } else {
+                // The messages were sent to a port, so concoct a URI for it
+                dispatchPortAddressedPdus(pdus, portAddrs.destPort);
             }
-
-            // Handle the PUSH
-            mWapPush.dispatchWapPdu(output.toByteArray());
-            break;
-        }
-
-        case -1:
+        } else {
             // The messages were not sent to a port
             dispatchPdus(pdus);
-            break;
-
-        default:
-            // The messages were sent to a port, so concoct a URI for it
-            dispatchPortAddressedPdus(pdus, destinationPort);
-            break;
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java
index 64b884e..d220648 100644
--- a/telephony/java/com/android/internal/telephony/SmsHeader.java
+++ b/telephony/java/com/android/internal/telephony/SmsHeader.java
@@ -16,227 +16,233 @@
 
 package com.android.internal.telephony;
 
+import android.telephony.SmsMessage;
+
 import com.android.internal.util.HexDump;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
 import java.util.ArrayList;
 
 /**
- * This class represents a SMS user data header.
- *
+ * SMS user data header, as specified in TS 23.040 9.2.3.24.
  */
 public class SmsHeader {
-    /** See TS 23.040 9.2.3.24 for description of this element ID. */
-    public static final int CONCATENATED_8_BIT_REFERENCE = 0x00;
-    /** See TS 23.040 9.2.3.24 for description of this element ID. */
-    public static final int SPECIAL_SMS_MESSAGE_INDICATION = 0x01;
-    /** See TS 23.040 9.2.3.24 for description of this element ID. */
-    public static final int APPLICATION_PORT_ADDRESSING_8_BIT = 0x04;
-    /** See TS 23.040 9.2.3.24 for description of this element ID. */
-    public static final int APPLICATION_PORT_ADDRESSING_16_BIT= 0x05;
-    /** See TS 23.040 9.2.3.24 for description of this element ID. */
-    public static final int CONCATENATED_16_BIT_REFERENCE = 0x08;
+
+    // TODO(cleanup): this datastructure is generally referred to as
+    // the 'user data header' or UDH, and so the class name should
+    // change to reflect this...
+
+    /** SMS user data header information element identifiers.
+     * (see TS 23.040 9.2.3.24)
+     */
+    public static final int ELT_ID_CONCATENATED_8_BIT_REFERENCE       = 0x00;
+    public static final int ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION     = 0x01;
+    public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT  = 0x04;
+    public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT = 0x05;
+    public static final int ELT_ID_SMSC_CONTROL_PARAMS                = 0x06;
+    public static final int ELT_ID_UDH_SOURCE_INDICATION              = 0x07;
+    public static final int ELT_ID_CONCATENATED_16_BIT_REFERENCE      = 0x08;
+    public static final int ELT_ID_WIRELESS_CTRL_MSG_PROTOCOL         = 0x09;
+    public static final int ELT_ID_TEXT_FORMATTING                    = 0x0A;
+    public static final int ELT_ID_PREDEFINED_SOUND                   = 0x0B;
+    public static final int ELT_ID_USER_DEFINED_SOUND                 = 0x0C;
+    public static final int ELT_ID_PREDEFINED_ANIMATION               = 0x0D;
+    public static final int ELT_ID_LARGE_ANIMATION                    = 0x0E;
+    public static final int ELT_ID_SMALL_ANIMATION                    = 0x0F;
+    public static final int ELT_ID_LARGE_PICTURE                      = 0x10;
+    public static final int ELT_ID_SMALL_PICTURE                      = 0x11;
+    public static final int ELT_ID_VARIABLE_PICTURE                   = 0x12;
+    public static final int ELT_ID_USER_PROMPT_INDICATOR              = 0x13;
+    public static final int ELT_ID_EXTENDED_OBJECT                    = 0x14;
+    public static final int ELT_ID_REUSED_EXTENDED_OBJECT             = 0x15;
+    public static final int ELT_ID_COMPRESSION_CONTROL                = 0x16;
+    public static final int ELT_ID_OBJECT_DISTR_INDICATOR             = 0x17;
+    public static final int ELT_ID_STANDARD_WVG_OBJECT                = 0x18;
+    public static final int ELT_ID_CHARACTER_SIZE_WVG_OBJECT          = 0x19;
+    public static final int ELT_ID_EXTENDED_OBJECT_DATA_REQUEST_CMD   = 0x1A;
+    public static final int ELT_ID_RFC_822_EMAIL_HEADER               = 0x20;
+    public static final int ELT_ID_HYPERLINK_FORMAT_ELEMENT           = 0x21;
+    public static final int ELT_ID_REPLY_ADDRESS_ELEMENT              = 0x22;
+    public static final int ELT_ID_ENHANCED_VOICE_MAIL_INFORMATION    = 0x23;
 
     public static final int PORT_WAP_PUSH = 2948;
-    public static final int PORT_WAP_WSP = 9200;
+    public static final int PORT_WAP_WSP  = 9200;
 
-    private byte[] m_data;
-    private ArrayList<Element> m_elements = new ArrayList<Element>();
-    public int nbrOfHeaders;
+    public static class PortAddrs {
+        public int destPort;
+        public int origPort;
+        public boolean areEightBits;
+    }
+
+    public static class ConcatRef {
+        public int refNumber;
+        public int seqNumber;
+        public int msgCount;
+        public boolean isEightBits;
+    }
 
     /**
-     * Creates an SmsHeader object from raw user data header bytes.
-     *
-     * @param data is user data header bytes
-     * @return an SmsHeader object
+     * A header element that is not explicitly parsed, meaning not
+     * PortAddrs or ConcatRef.
      */
-    public static SmsHeader parse(byte[] data) {
-        SmsHeader header = new SmsHeader();
-        header.m_data = data;
+    public static class MiscElt {
+        public int id;
+        public byte[] data;
+    }
 
-        int index = 0;
-        header.nbrOfHeaders = 0;
-        while (index < data.length) {
-            int id = data[index++] & 0xff;
-            int length = data[index++] & 0xff;
-            byte[] elementData = new byte[length];
-            System.arraycopy(data, index, elementData, 0, length);
-            header.add(new Element(id, elementData));
-            index += length;
-            header.nbrOfHeaders++;
+    public PortAddrs portAddrs;
+    public ConcatRef concatRef;
+    public ArrayList<MiscElt> miscEltList = new ArrayList<MiscElt>();
+
+    public SmsHeader() {}
+
+    /**
+     * Create structured SmsHeader object from serialized byte array representation.
+     * (see TS 23.040 9.2.3.24)
+     * @param data is user data header bytes
+     * @return SmsHeader object
+     */
+    public static SmsHeader fromByteArray(byte[] data) {
+        ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+        SmsHeader smsHeader = new SmsHeader();
+        while (inStream.available() > 0) {
+            /**
+             * NOTE: as defined in the spec, ConcatRef and PortAddr
+             * fields should not reoccur, but if they do the last
+             * occurrence is to be used.
+             */
+            int id = inStream.read();
+            int length = inStream.read();
+            ConcatRef concatRef;
+            PortAddrs portAddrs;
+            switch (id) {
+            case ELT_ID_CONCATENATED_8_BIT_REFERENCE:
+                concatRef = new ConcatRef();
+                concatRef.refNumber = inStream.read();
+                concatRef.msgCount = inStream.read();
+                concatRef.seqNumber = inStream.read();
+                concatRef.isEightBits = true;
+                smsHeader.concatRef = concatRef;
+                break;
+            case ELT_ID_CONCATENATED_16_BIT_REFERENCE:
+                concatRef = new ConcatRef();
+                concatRef.refNumber = (inStream.read() << 8) | inStream.read();
+                concatRef.msgCount = inStream.read();
+                concatRef.seqNumber = inStream.read();
+                concatRef.isEightBits = false;
+                smsHeader.concatRef = concatRef;
+                break;
+            case ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT:
+                portAddrs = new PortAddrs();
+                portAddrs.destPort = inStream.read();
+                portAddrs.origPort = inStream.read();
+                portAddrs.areEightBits = true;
+                smsHeader.portAddrs = portAddrs;
+                break;
+            case ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT:
+                portAddrs = new PortAddrs();
+                portAddrs.destPort = (inStream.read() << 8) | inStream.read();
+                portAddrs.origPort = (inStream.read() << 8) | inStream.read();
+                portAddrs.areEightBits = false;
+                smsHeader.portAddrs = portAddrs;
+                break;
+            default:
+                MiscElt miscElt = new MiscElt();
+                miscElt.id = id;
+                miscElt.data = new byte[length];
+                inStream.read(miscElt.data, 0, length);
+                smsHeader.miscEltList.add(miscElt);
+            }
+        }
+        return smsHeader;
+    }
+
+    /**
+     * Create serialized byte array representation from structured SmsHeader object.
+     * (see TS 23.040 9.2.3.24)
+     * @return Byte array representing the SmsHeader
+     */
+    public static byte[] toByteArray(SmsHeader smsHeader) {
+        if ((smsHeader.portAddrs == null) &&
+            (smsHeader.concatRef == null) &&
+            (smsHeader.miscEltList.size() == 0)) {
+            return null;
         }
 
-        return header;
-    }
-
-    public SmsHeader() { }
-
-    /**
-     * Returns the list of SmsHeader Elements that make up the header.
-     *
-     * @return the list of SmsHeader Elements.
-     */
-    public ArrayList<Element> getElements() {
-        return m_elements;
-    }
-
-    /**
-     * Add an element to the SmsHeader.
-     *
-     * @param element to add.
-     */
-    public void add(Element element) {
-        m_elements.add(element);
+        ByteArrayOutputStream outStream = new ByteArrayOutputStream(SmsMessage.MAX_USER_DATA_BYTES);
+        ConcatRef concatRef = smsHeader.concatRef;
+        if (concatRef != null) {
+            if (concatRef.isEightBits) {
+                outStream.write(ELT_ID_CONCATENATED_8_BIT_REFERENCE);
+                outStream.write(3);
+                outStream.write(concatRef.refNumber);
+            } else {
+                outStream.write(ELT_ID_CONCATENATED_16_BIT_REFERENCE);
+                outStream.write(4);
+                outStream.write(concatRef.refNumber >>> 8);
+                outStream.write(concatRef.refNumber & 0x00FF);
+            }
+            outStream.write(concatRef.msgCount);
+            outStream.write(concatRef.seqNumber);
+        }
+        PortAddrs portAddrs = smsHeader.portAddrs;
+        if (portAddrs != null) {
+            if (portAddrs.areEightBits) {
+                outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT);
+                outStream.write(2);
+                outStream.write(portAddrs.destPort);
+                outStream.write(portAddrs.origPort);
+            } else {
+                outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT);
+                outStream.write(4);
+                outStream.write(portAddrs.destPort >>> 8);
+                outStream.write(portAddrs.destPort & 0x00FF);
+                outStream.write(portAddrs.origPort >>> 8);
+                outStream.write(portAddrs.origPort & 0x00FF);
+            }
+        }
+        for (MiscElt miscElt : smsHeader.miscEltList) {
+            outStream.write(miscElt.id);
+            outStream.write(miscElt.data.length);
+            outStream.write(miscElt.data, 0, miscElt.data.length);
+        }
+        return outStream.toByteArray();
     }
 
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-
-        builder.append("UDH LENGTH: " + m_data.length + " octets");
-        builder.append("UDH: ");
-        builder.append(HexDump.toHexString(m_data));
-        builder.append("\n");
-
-        for (Element e : getElements()) {
-            builder.append("  0x" + HexDump.toHexString((byte)e.getID()) + " - ");
-            switch (e.getID()) {
-                case CONCATENATED_8_BIT_REFERENCE: {
-                    builder.append("Concatenated Short Message 8bit ref\n");
-                    byte[] data = e.getData();
-                    builder.append("    " + data.length + " (0x");
-                    builder.append(HexDump.toHexString((byte)data.length)
-                            + ") Bytes - Information Element\n");
-                    builder.append("      " + data[0] + " : SM reference number\n");
-                    builder.append("      " + data[1] + " : number of messages\n");
-                    builder.append("      " + data[2] + " : this SM sequence number\n");
-                    break;
-                }
-
-                case CONCATENATED_16_BIT_REFERENCE: {
-                    builder.append("Concatenated Short Message 16bit ref\n");
-                    byte[] data = e.getData();
-                    builder.append("    " + data.length + " (0x");
-                    builder.append(HexDump.toHexString((byte)data.length)
-                            + ") Bytes - Information Element\n");
-                    builder.append("      " + (data[0] & 0xff) * 256 + (data[1] & 0xff)
-                            + " : SM reference number\n");
-                    builder.append("      " + data[2] + " : number of messages\n");
-                    builder.append("      " + data[3] + " : this SM sequence number\n");
-                    break;
-                }
-
-                case APPLICATION_PORT_ADDRESSING_8_BIT:
-                {
-                    builder.append("Application port addressing 8bit\n");
-                    byte[] data = e.getData();
-
-                    builder.append("    " + data.length + " (0x");
-                    builder.append(HexDump.toHexString(
-                            (byte)data.length) + ") Bytes - Information Element\n");
-
-                    int source = (data[0] & 0xff);
-                    builder.append("      " + source + " : DESTINATION port\n");
-
-                    int dest = (data[1] & 0xff);
-                    builder.append("      " + dest + " : SOURCE port\n");
-                    break;
-                }
-
-                case APPLICATION_PORT_ADDRESSING_16_BIT: {
-                    builder.append("Application port addressing 16bit\n");
-                    byte[] data = e.getData();
-
-                    builder.append("    " + data.length + " (0x");
-                    builder.append(HexDump.toHexString((byte)data.length)
-                            + ") Bytes - Information Element\n");
-
-                    int source = (data[0] & 0xff) << 8;
-                    source |= (data[1] & 0xff);
-                    builder.append("      " + source + " : DESTINATION port\n");
-
-                    int dest = (data[2] & 0xff) << 8;
-                    dest |= (data[3] & 0xff);
-                    builder.append("      " + dest + " : SOURCE port\n");
-                    break;
-                }
-
-                default: {
-                    builder.append("Unknown element\n");
-                    break;
-                }
-            }
+        builder.append("UserDataHeader ");
+        builder.append("{ ConcatRef ");
+        if (concatRef == null) {
+            builder.append("unset");
+        } else {
+            builder.append("{ refNumber=" + concatRef.refNumber);
+            builder.append(", msgCount=" + concatRef.msgCount);
+            builder.append(", seqNumber=" + concatRef.seqNumber);
+            builder.append(", isEightBits=" + concatRef.isEightBits);
+            builder.append(" }");
         }
-
+        builder.append(", PortAddrs ");
+        if (portAddrs == null) {
+            builder.append("unset");
+        } else {
+            builder.append("{ destPort=" + portAddrs.destPort);
+            builder.append(", origPort=" + portAddrs.origPort);
+            builder.append(", areEightBits=" + portAddrs.areEightBits);
+            builder.append(" }");
+        }
+        for (MiscElt miscElt : miscEltList) {
+            builder.append(", MiscElt ");
+            builder.append("{ id=" + miscElt.id);
+            builder.append(", length=" + miscElt.data.length);
+            builder.append(", data=" + HexDump.toHexString(miscElt.data));
+            builder.append(" }");
+        }
+        builder.append(" }");
         return builder.toString();
     }
 
-    private int calcSize() {
-        int size = 1; // +1 for the UDHL field
-        for (Element e : m_elements) {
-            size += e.getData().length;
-            size += 2; // 1 byte ID, 1 byte length
-        }
-
-        return size;
-    }
-
-    /**
-     * Converts SmsHeader object to a byte array as specified in TS 23.040 9.2.3.24.
-     * @return Byte array representing the SmsHeader
-     */
-    public byte[] toByteArray() {
-        if (m_elements.size() == 0) return null;
-
-        if (m_data == null) {
-            int size = calcSize();
-            int cur = 1;
-            m_data = new byte[size];
-
-            m_data[0] = (byte) (size-1);  // UDHL does not include itself
-
-            for (Element e : m_elements) {
-                int length = e.getData().length;
-                m_data[cur++] = (byte) e.getID();
-                m_data[cur++] = (byte) length;
-                System.arraycopy(e.getData(), 0, m_data, cur, length);
-                cur += length;
-            }
-        }
-
-        return m_data;
-    }
-
-    /**
-     * A single Element in the SMS User Data Header.
-     *
-     * See TS 23.040 9.2.3.24.
-     *
-     */
-    public static class Element {
-        private byte[] m_data;
-        private int m_id;
-
-        public Element(int id, byte[] data) {
-            m_id = id;
-            m_data = data;
-        }
-
-        /**
-         * Returns the Information Element Identifier for this element.
-         *
-         * @return the IE identifier.
-         */
-        public int getID() {
-            return m_id;
-        }
-
-        /**
-         * Returns the data portion of this element.
-         *
-         * @return element data.
-         */
-        public byte[] getData() {
-            return m_data;
-        }
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 1aad38d..31bb652 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -245,8 +245,6 @@
     /**
      * Returns an object representing the user data header
      *
-     * @return an object representing the user data header
-     *
      * {@hide}
      */
     public SmsHeader getUserDataHeader() {
@@ -254,9 +252,14 @@
     }
 
     /**
+     * TODO(cleanup): The term PDU is used in a seemingly non-unique
+     * manner -- for example, what is the difference between this byte
+     * array and the contents of SubmitPdu objects.  Maybe a more
+     * illustrative term would be appropriate.
+     */
+
+    /**
      * Returns the raw PDU for the message.
-     *
-     * @return the raw PDU for the message.
      */
     public byte[] getPdu() {
         return mPdu;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 67ae169..453185f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -69,6 +69,8 @@
      */
     static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country";
 
+    static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
+
     //****** SIM Card
     /**
      * One of <code>"UNKNOWN"</code> <code>"ABSENT"</code> <code>"PIN_REQUIRED"</code>
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 3f8d40c..03f7f98 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -52,6 +52,7 @@
 import com.android.internal.telephony.PhoneSubInfo;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -126,8 +127,8 @@
 
 
         //Change the system setting
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE);
+        SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+                new Integer(RILConstants.CDMA_PHONE).toString());
     }
 
     public void dispose() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 42c0583..2bb17e4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -29,7 +29,6 @@
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SMSDispatcher;
-//import com.android.internal.telephony.SMSDispatcher.SmsTracker;
 import com.android.internal.telephony.cdma.SmsMessage;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.util.HexDump;
@@ -42,8 +41,11 @@
 final class CdmaSMSDispatcher extends SMSDispatcher {
     private static final String TAG = "CDMA";
 
+    private CDMAPhone mCdmaPhone;
+
     CdmaSMSDispatcher(CDMAPhone phone) {
         super(phone);
+        mCdmaPhone = phone;
     }
 
     /**
@@ -70,50 +72,39 @@
         if (smsb == null) {
             return;
         }
-        SmsMessage sms = (SmsMessage) smsb;
-        int teleService;
-        boolean handled = false;
 
         // Decode BD stream and set sms variables.
+        SmsMessage sms = (SmsMessage) smsb;
         sms.parseSms();
-        teleService = sms.getTeleService();
+        int teleService = sms.getTeleService();
+        boolean handled = false;
 
         // Teleservices W(E)MT and VMN are handled together:
-        if ((SmsEnvelope.TELESERVICE_WMT == teleService)
-                ||(SmsEnvelope.TELESERVICE_WEMT == teleService)
-                ||(SmsEnvelope.TELESERVICE_VMN == teleService)){
+        if ((teleService == SmsEnvelope.TELESERVICE_WMT)
+                || (teleService == SmsEnvelope.TELESERVICE_WEMT)
+                || (teleService == SmsEnvelope.TELESERVICE_VMN)) {
             // From here on we need decoded BD.
             // Special case the message waiting indicator messages
             if (sms.isMWISetMessage()) {
-                ((CDMAPhone) mPhone).updateMessageWaitingIndicator(true);
-
-                if (sms.isMwiDontStore()) {
-                    handled = true;
-                }
-
+                mCdmaPhone.updateMessageWaitingIndicator(true);
+                handled |= sms.isMwiDontStore();
                 if (Config.LOGD) {
-                    Log.d(TAG,
-                            "Received voice mail indicator set SMS shouldStore=" + !handled);
+                    Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
                 }
             } else if (sms.isMWIClearMessage()) {
-                ((CDMAPhone) mPhone).updateMessageWaitingIndicator(false);
-
-                if (sms.isMwiDontStore()) {
-                    handled = true;
-                }
-
+                mCdmaPhone.updateMessageWaitingIndicator(false);
+                handled |= sms.isMwiDontStore();
                 if (Config.LOGD) {
-                    Log.d(TAG,
-                            "Received voice mail indicator clear SMS shouldStore=" + !handled);
+                    Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
                 }
             }
         }
 
-        if (null == sms.getUserData()){
-            handled = true;
+        if (sms.getUserData() == null) {
             if (Config.LOGD) {
                 Log.d(TAG, "Received SMS without user data");
             }
+            handled = true;
         }
 
         if (handled) return;
@@ -123,82 +114,44 @@
             return;
         }
 
-        // Parse the headers to see if this is partial, or port addressed
-        int referenceNumber = -1;
-        int count = 0;
-        int sequence = 0;
-        int destPort = -1;
-        // From here on we need BD distributed to SMS member variables.
+        /**
+         * TODO(cleanup): Why are we using a getter method for this
+         * (and for so many other sms fields)?  Trivial getters and
+         * setters like this are direct violations of the style guide.
+         * If the purpose is to protect agaist writes (by not
+         * providing a setter) then any protection is illusory (and
+         * hence bad) for cases where the values are not primitives,
+         * such as this call for the header.  Since this is an issue
+         * with the public API it cannot be changed easily, but maybe
+         * something can be done eventually.
+         */
+        SmsHeader smsHeader = sms.getUserDataHeader();
 
-        SmsHeader header = sms.getUserDataHeader();
-        if (header != null) {
-            for (SmsHeader.Element element : header.getElements()) {
-                try {
-                    switch (element.getID()) {
-                        case SmsHeader.CONCATENATED_8_BIT_REFERENCE: {
-                            byte[] data = element.getData();
-                            
-                            referenceNumber = data[0] & 0xff;
-                            count = data[1] & 0xff;
-                            sequence = data[2] & 0xff;
-                            
-                            // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence
-                            // is zero, or sequence > count, ignore the entire element
-                            if (count == 0 || sequence == 0 || sequence > count) {
-                                referenceNumber = -1;
-                            }
-                            break;
-                        }
-                        
-                        case SmsHeader.CONCATENATED_16_BIT_REFERENCE: {
-                            byte[] data = element.getData();
-                            
-                            referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff);
-                            count = data[2] & 0xff;
-                            sequence = data[3] & 0xff;
-                            
-                            // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence
-                            // is zero, or sequence > count, ignore the entire element
-                            if (count == 0 || sequence == 0 || sequence > count) {
-                                referenceNumber = -1;
-                            }
-                            break;
-                        }
-                        
-                        case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: {
-                            byte[] data = element.getData();
-                            
-                            destPort = (data[0] & 0xff) << 8;
-                            destPort |= (data[1] & 0xff);
-                            
-                            break;
-                        }
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    Log.e(TAG, "Bad element in header", e);
-                    return;  // TODO: NACK the message or something, don't just discard.
-                }
-            }
-        }
-
-        if (referenceNumber == -1) {
-            // notify everyone of the message if it isn't partial
+        /**
+         * TODO(cleanup): Since both CDMA and GSM use the same header
+         * format, this dispatch processing is naturally identical,
+         * and code should probably not be replicated explicitly.
+         */
+        // See if message is partial or port addressed.
+        if ((smsHeader == null) || (smsHeader.concatRef == null)) {
+            // Message is not partial (not part of concatenated sequence).
             byte[][] pdus = new byte[1][];
             pdus[0] = sms.getPdu();
 
-            if (destPort != -1) {// GSM-style WAP indication
-                if (destPort == SmsHeader.PORT_WAP_PUSH) {
+            if (smsHeader.portAddrs != null) {
+                if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
+                    // GSM-style WAP indication
                     mWapPush.dispatchWapPdu(sms.getUserData());
                 }
-                // The message was sent to a port, so concoct a URI for it
-                dispatchPortAddressedPdus(pdus, destPort);
+                // The message was sent to a port, so concoct a URI for it.
+                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
             } else {
-                // It's a normal message, dispatch it
+                // Normal short and non-port-addressed message, dispatch it.
                 dispatchPdus(pdus);
             }
         } else {
-            // Process the message part
-            processMessagePart(sms, referenceNumber, sequence, count, destPort);
+            // Process the message part.
+            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
         }
     }
 
@@ -314,41 +267,49 @@
     }
 
     /** {@inheritDoc} */
-    protected void sendMultipartText(String destinationAddress, String scAddress,
+    protected void sendMultipartText(String destAddr, String scAddr,
             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
             ArrayList<PendingIntent> deliveryIntents) {
 
-        int ref = ++sConcatenatedRef & 0xff;
+        /**
+         * TODO(cleanup): There is no real code difference between
+         * this and the GSM version, and hence it should be moved to
+         * the base class or consolidated somehow, provided calling
+         * the proper submitpdu stuff can be arranged.
+         */
 
-        for (int i = 0, count = parts.size(); i < count; i++) {
-            // build SmsHeader data
-            byte[] data = new byte[5];
-            data[0] = (byte) SmsHeader.CONCATENATED_8_BIT_REFERENCE;
-            data[1] = (byte) 3;   // 3 bytes follow
-            data[2] = (byte) ref;   // reference #, unique per message
-            data[3] = (byte) count; // total part count
-            data[4] = (byte) (i + 1);  // 1-based sequence
+        int refNumber = getNextConcatenatedRef() & 0x00FF;
+
+        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+            concatRef.refNumber = refNumber;
+            concatRef.seqNumber = i + 1;  // 1-based sequence
+            concatRef.msgCount = msgCount;
+            concatRef.isEightBits = true;
+            SmsHeader smsHeader = new SmsHeader();
+            smsHeader.concatRef = concatRef;
 
             PendingIntent sentIntent = null;
-            PendingIntent deliveryIntent = null;
-
             if (sentIntents != null && sentIntents.size() > i) {
                 sentIntent = sentIntents.get(i);
             }
+
+            PendingIntent deliveryIntent = null;
             if (deliveryIntents != null && deliveryIntents.size() > i) {
                 deliveryIntent = deliveryIntents.get(i);
             }
 
-            SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, data);
+            SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(scAddr, destAddr,
+                    parts.get(i), deliveryIntent != null, smsHeader);
 
-            sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
+            sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
         }
     }
 
-    protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
+    protected void sendSubmitPdu(SmsMessage.SubmitPdu submitPdu, PendingIntent sentIntent,
             PendingIntent deliveryIntent) {
-        super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
+        sendRawPdu(submitPdu.encodedScAddress, submitPdu.encodedMessage,
+                sentIntent, deliveryIntent);
     }
 
     /** {@inheritDoc} */
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 343a22e..b2083ed 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -277,6 +277,15 @@
     }
 
     /**
+     * TODO(cleanup): why do getSubmitPdu methods take an scAddr input
+     * and do nothing with it?  GSM allows us to specify a SC (eg,
+     * when responding to an SMS that explicitly requests the response
+     * is sent to a specific SC), or pass null to use the default
+     * value.  Is there no similar notion in CDMA? Or do we just not
+     * have it hooked up?
+     */
+
+    /**
      * Get an SMS-SUBMIT PDU for a destination address and a message
      *
      * @param scAddr                Service Centre address.  Null means use default.
@@ -290,88 +299,53 @@
      *         Returns null on encode error.
      * @hide
      */
-    public static SubmitPdu getSubmitPdu(String scAddr,
-            String destAddr, String message,
-            boolean statusReportRequested, byte[] headerData) {
-        /**
-         * TODO(cleanup): why does this method take an scAddr input
-         * and do nothing with it?  GSM allows us to specify a SC (eg,
-         * when responding to an SMS that explicitly requests the
-         * response is sent to a specific SC), or pass null to use the
-         * default value.  Is there no similar notion in CDMA? Or do
-         * we just not have it hooked up?
-         */
+    public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
+            boolean statusReportRequested, SmsHeader smsHeader) {
 
+        /**
+         * TODO(cleanup): Do we really want silent failure like this?
+         * Would it not be much more reasonable to make sure we don't
+         * call this function if we really want nothing done?
+         */
         if (message == null || destAddr == null) {
             return null;
         }
 
         UserData uData = new UserData();
         uData.payloadStr = message;
-        if(headerData != null) {
-            /**
-             * TODO(cleanup): we force the outside to deal with _all_
-             * of the raw details of properly constructing serialized
-             * headers, unserialze here, and then promptly reserialze
-             * during encoding -- rather undesirable.
-             */
-            uData.userDataHeader = SmsHeader.parse(headerData);
-        }
-
-        return privateGetSubmitPdu(destAddr, statusReportRequested, uData, (headerData == null));
-    }
-
-
-    /**
-     * Get an SMS-SUBMIT PDU for a destination address and a message
-     *
-     * @param scAddress Service Centre address.  Null means use default.
-     * @return a <code>SubmitPdu</code> containing the encoded SC
-     *         address, if applicable, and the encoded message.
-     *         Returns null on encode error.
-     */
-    public static SubmitPdu getSubmitPdu(String scAddress,
-            String destinationAddress, String message,
-            boolean statusReportRequested) {
-        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null);
+        uData.userDataHeader = smsHeader;
+        return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
     }
 
     /**
      * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
      *
-     * @param scAddress Service Centre address. null == use default
-     * @param destinationAddress the address of the destination for the message
-     * @param destinationPort the port to deliver the message to at the
+     * @param scAddr Service Centre address. null == use default
+     * @param destAddr the address of the destination for the message
+     * @param destPort the port to deliver the message to at the
      *        destination
      * @param data the data for the message
      * @return a <code>SubmitPdu</code> containing the encoded SC
      *         address, if applicable, and the encoded message.
      *         Returns null on encode error.
      */
-    public static SubmitPdu getSubmitPdu(String scAddress,
-            String destAddr, short destinationPort, byte[] data,
-            boolean statusReportRequested) {
+    public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, short destPort,
+            byte[] data, boolean statusReportRequested) {
 
         /**
-         * TODO(cleanup): if we had properly exposed SmsHeader
-         * information, this mess of many getSubmitPdu public
-         * interface methods that currently pollute the api could have
-         * been much more cleanly collapsed into one.
+         * TODO(cleanup): this is not a general-purpose SMS creation
+         * method, but rather something specialized to messages
+         * containing OCTET encoded (meaning non-human-readable) user
+         * data.  The name should reflect that, and not just overload.
          */
 
-        /**
-         * TODO(cleanup): header serialization should be put somewhere
-         * canonical to allow proper debugging and reuse.
-         */
-        byte[] destPort = new byte[4];
-        destPort[0] = (byte) ((destinationPort >> 8) & 0xFF); // MSB of destination port
-        destPort[1] = (byte) (destinationPort & 0xFF); // LSB of destination port
-        destPort[2] = 0x00; // MSB of originating port
-        destPort[3] = 0x00; // LSB of originating port
+        SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
+        portAddrs.destPort = destPort;
+        portAddrs.origPort = 0;
+        portAddrs.areEightBits = false;
+
         SmsHeader smsHeader = new SmsHeader();
-        smsHeader.add(
-                new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort));
-        smsHeader.nbrOfHeaders = smsHeader.getElements().size();
+        smsHeader.portAddrs = portAddrs;
 
         UserData uData = new UserData();
         uData.userDataHeader = smsHeader;
@@ -379,7 +353,7 @@
         uData.msgEncodingSet = true;
         uData.payload = data;
 
-        return privateGetSubmitPdu(destAddr, statusReportRequested, uData, true);
+        return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
     }
 
     static class PduParser {
@@ -445,31 +419,23 @@
      * {@inheritDoc}
      */
     public boolean isMWIClearMessage() {
-        if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) {
-            return true;
-        }
-        return false;
+        return ((mBearerData != null) && (mBearerData.numberOfMessages == 0));
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean isMWISetMessage() {
-        if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) {
-            return true;
-        }
-        return false;
+        return ((mBearerData != null) && (mBearerData.numberOfMessages > 0));
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean isMwiDontStore() {
-        if ((mBearerData != null) && (mBearerData.numberOfMessages >0)
-                && (null == mBearerData.userData)) {
-            return true;
-        }
-        return false;
+        return ((mBearerData != null) &&
+                (mBearerData.numberOfMessages > 0) &&
+                (mBearerData.userData == null));
     }
 
     /**
@@ -478,7 +444,7 @@
      * shifted to the bits 31-16.
      */
     public int getStatus() {
-        return(status<<16);
+        return (status << 16);
     }
 
     /**
@@ -518,7 +484,7 @@
      */
     private void parsePdu(byte[] pdu) {
         ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
-        DataInputStream dis = new DataInputStream(new BufferedInputStream(bais));
+        DataInputStream dis = new DataInputStream(bais);
         byte length;
         int bearerDataLength;
         SmsEnvelope env = new SmsEnvelope();
@@ -568,38 +534,23 @@
     protected void parseSms() {
         mBearerData = BearerData.decode(mEnvelope.bearerData);
         messageRef = mBearerData.messageId;
+        if (mBearerData.userData != null) {
+            userData = mBearerData.userData.payload;
+            userDataHeader = mBearerData.userData.userDataHeader;
+            messageBody = mBearerData.userData.payloadStr;
+        }
 
-        // TP-Message-Type-Indicator
-        // (See 3GPP2 C.S0015-B, v2, 4.5.1)
-        int messageType = mBearerData.messageType;
-
-        switch (messageType) {
+        // TP-Message-Type-Indicator (See 3GPP2 C.S0015-B, v2, 4.5.1)
+        switch (mBearerData.messageType) {
         case BearerData.MESSAGE_TYPE_USER_ACK:
         case BearerData.MESSAGE_TYPE_READ_ACK:
         case BearerData.MESSAGE_TYPE_DELIVER:
-            // Deliver (mobile-terminated only)
-            parseSmsDeliver();
-            break;
         case BearerData.MESSAGE_TYPE_DELIVERY_ACK:
-            parseSmsDeliveryAck();
             break;
-
         default:
-            // the rest of these
-            throw new RuntimeException("Unsupported message type: " + messageType);
+            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
         }
-    }
 
-    /**
-     * TODO(cleanup): why are there two nearly identical functions
-     * below?  More rubbish...
-     */
-
-    /**
-     * Parses a SMS-DELIVER message. (mobile-terminated only)
-     * See 3GPP2 C.S0015-B, v2, 4.4.1
-     */
-    private void parseSmsDeliver() {
         if (originatingAddress != null) {
             originatingAddress.address = new String(originatingAddress.origBytes);
             if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
@@ -612,46 +563,13 @@
 
         if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
 
-        parseUserData(mBearerData.userData);
-    }
-
-    /**
-     * Parses a SMS-DELIVER message. (mobile-terminated only)
-     * See 3GPP2 C.S0015-B, v2, 4.4.1
-     */
-    private void parseSmsDeliveryAck() {
-        if (originatingAddress != null) {
-            originatingAddress.address = new String(originatingAddress.origBytes);
-            if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
-                    + originatingAddress.address);
-        }
-
-        if (mBearerData.timeStamp != null) {
-                scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp);
-        }
-
-        if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
-
-        if (mBearerData.errorClass != BearerData.ERROR_UNDEFINED) {
+        // TODO(Teleca): do we really want this test to occur only for DELIVERY_ACKs?
+        if ((mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) &&
+                (mBearerData.errorClass != BearerData.ERROR_UNDEFINED)) {
             status = mBearerData.errorClass << 8;
             status |= mBearerData.messageStatus;
         }
 
-        parseUserData(mBearerData.userData);
-    }
-
-    /**
-     * Copy parsed user data out from internal datastructures.
-     */
-    private void parseUserData(UserData uData) {
-        if (uData == null) {
-            return;
-        }
-
-        userData = uData.payload;
-        userDataHeader = uData.userDataHeader;
-        messageBody = uData.payloadStr;
-
         if (messageBody != null) {
             if (Config.LOGV) Log.v(LOG_TAG, "SMS message body: '" + messageBody + "'");
             parseMessageBody();
@@ -708,7 +626,7 @@
      * @return byte stream for SubmitPdu.
      */
     private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
-            UserData userData, boolean useNewId) {
+            UserData userData) {
 
         /**
          * TODO(cleanup): give this function a more meaningful name.
@@ -720,7 +638,7 @@
         BearerData bearerData = new BearerData();
         bearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
 
-        if (useNewId) setNextMessageId();
+        if (userData != null) setNextMessageId();
         bearerData.messageId = nextMessageId;
 
         bearerData.deliveryAckReq = statusReportRequested;
@@ -812,6 +730,15 @@
             dos.write(env.bearerData, 0, env.bearerData.length);
             dos.close();
 
+            /**
+             * TODO(cleanup) -- This is the only place where mPdu is
+             * defined, and this is not obviously the only place where
+             * it needs to be defined.  It would be much nicer if
+             * accessing the serialized representation used a less
+             * fragile mechanism.  Maybe the getPdu method could
+             * generate a representation if there was not yet one?
+             */
+
             mPdu = baos.toByteArray();
         } catch (IOException ex) {
             Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex);
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 e64d022..05c8c9d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -189,8 +189,12 @@
     public int messageStatus = STATUS_UNDEFINED;
 
     /**
-     * 1-bit value that indicates whether a User Data Header is present.
+     * 1-bit value that indicates whether a User Data Header (UDH) is present.
      * (See 3GPP2 C.S0015-B, v2, 4.5.1)
+     *
+     * NOTE: during encoding, this value will be set based on the
+     * presence of a UDH in the structured data, any existing setting
+     * will be overwritten.
      */
     public boolean hasUserDataHeader;
 
@@ -248,25 +252,27 @@
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-        builder.append("BearerData:\n");
-        builder.append("  messageType: " + messageType + "\n");
-        builder.append("  messageId: " + (int)messageId + "\n");
-        builder.append("  priority: " + (priorityIndicatorSet ? priority : "not set") + "\n");
-        builder.append("  privacy: " + (privacyIndicatorSet ? privacy : "not set") + "\n");
-        builder.append("  alert: " + (alertIndicatorSet ? alert : "not set") + "\n");
-        builder.append("  displayMode: " + (displayModeSet ? displayMode : "not set") + "\n");
-        builder.append("  language: " + (languageIndicatorSet ? language : "not set") + "\n");
-        builder.append("  errorClass: " + (messageStatusSet ? errorClass : "not set") + "\n");
-        builder.append("  msgStatus: " + (messageStatusSet ? messageStatus : "not set") + "\n");
-        builder.append("  hasUserDataHeader: " + hasUserDataHeader + "\n");
-        builder.append("  timeStamp: " + timeStamp + "\n");
-        builder.append("  userAckReq: " + userAckReq + "\n");
-        builder.append("  deliveryAckReq: " + deliveryAckReq + "\n");
-        builder.append("  readAckReq: " + readAckReq + "\n");
-        builder.append("  reportReq: " + reportReq + "\n");
-        builder.append("  numberOfMessages: " + numberOfMessages + "\n");
-        builder.append("  callbackNumber: " + callbackNumber + "\n");
-        builder.append("  userData: " + userData + "\n");
+        builder.append("BearerData ");
+        builder.append("{ messageType=" + messageType);
+        builder.append(", messageId=" + (int)messageId);
+        builder.append(", priority=" + (priorityIndicatorSet ? priority : "unset"));
+        builder.append(", privacy=" + (privacyIndicatorSet ? privacy : "unset"));
+        builder.append(", alert=" + (alertIndicatorSet ? alert : "unset"));
+        builder.append(", displayMode=" + (displayModeSet ? displayMode : "unset"));
+        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(", userAckReq=" + userAckReq);
+        builder.append(", deliveryAckReq=" + deliveryAckReq);
+        builder.append(", readAckReq=" + readAckReq);
+        builder.append(", reportReq=" + reportReq);
+        builder.append(", numberOfMessages=" + numberOfMessages);
+        builder.append(", callbackNumber=" + callbackNumber);
+        builder.append(", hasUserDataHeader=" + hasUserDataHeader);
+        builder.append(", userData=" + userData);
+        builder.append(" }");
         return builder.toString();
     }
 
@@ -335,12 +341,19 @@
     private static void encodeUserDataPayload(UserData uData)
         throws CodingException
     {
+        byte[] headerData = null;
+        if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
+        int headerDataLen = (headerData == null) ? 0 : headerData.length + 1;  // + length octet
+
+        byte[] payloadData;
         if (uData.msgEncodingSet) {
             if (uData.msgEncoding == UserData.ENCODING_OCTET) {
                 if (uData.payload == null) {
                     Log.e(LOG_TAG, "user data with octet encoding but null payload");
                     // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
-                    uData.payload = new byte[0];
+                    payloadData = new byte[0];
+                } else {
+                    payloadData = uData.payload;
                 }
             } else {
                 if (uData.payloadStr == null) {
@@ -349,11 +362,11 @@
                     uData.payloadStr = "";
                 }
                 if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
-                    uData.payload = encode7bitGsm(uData.payloadStr);
+                    payloadData = encode7bitGsm(uData.payloadStr);
                 } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
-                    uData.payload = encode7bitAscii(uData.payloadStr);
+                    payloadData = encode7bitAscii(uData.payloadStr);
                 } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
-                    uData.payload = encodeUtf16(uData.payloadStr);
+                    payloadData = encodeUtf16(uData.payloadStr);
                 } else {
                     throw new CodingException("unsupported user data encoding (" +
                                               uData.msgEncoding + ")");
@@ -367,19 +380,28 @@
                 uData.payloadStr = "";
             }
             try {
-                uData.payload = encode7bitAscii(uData.payloadStr);
+                payloadData = encode7bitAscii(uData.payloadStr);
                 uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
             } catch (CodingException ex) {
-                uData.payload = encodeUtf16(uData.payloadStr);
+                payloadData = encodeUtf16(uData.payloadStr);
                 uData.msgEncoding = UserData.ENCODING_UNICODE_16;
             }
             uData.msgEncodingSet = true;
             uData.numFields = uData.payloadStr.length();
         }
-        if (uData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) {
-            throw new CodingException("encoded user data too large (" + uData.payload.length +
+
+        int totalLength = payloadData.length + headerDataLen;
+        if (totalLength > SmsMessage.MAX_USER_DATA_BYTES) {
+            throw new CodingException("encoded user data too large (" + totalLength +
                                       " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
         }
+
+        uData.payload = new byte[totalLength];
+        if (headerData != null) {
+            uData.payload[0] = (byte)headerData.length;
+            System.arraycopy(headerData, 0, uData.payload, 1, headerData.length);
+        }
+        System.arraycopy(payloadData, 0, uData.payload, headerDataLen, payloadData.length);
     }
 
     private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
@@ -394,11 +416,6 @@
          *
          */
         int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits;
-        byte[] headerData = null;
-        if (bData.hasUserDataHeader) {
-            headerData = bData.userData.userDataHeader.toByteArray();
-            dataBits += headerData.length * 8;
-        }
         int paramBits = dataBits + 13;
         if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
             (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
@@ -413,7 +430,6 @@
             outStream.write(8, bData.userData.msgType);
         }
         outStream.write(8, bData.userData.numFields);
-        if (headerData != null) outStream.writeByteArray(headerData.length * 8, headerData);
         outStream.writeByteArray(dataBits, bData.userData.payload);
         if (paddingBits > 0) outStream.write(paddingBits, 0);
     }
@@ -557,6 +573,8 @@
      * @return data byta array of raw encoded SMS bearer data.
      */
     public static byte[] encode(BearerData bData) {
+        bData.hasUserDataHeader = ((bData.userData != null) &&
+                (bData.userData.userDataHeader != null));
         try {
             BitwiseOutputStream outStream = new BitwiseOutputStream(200);
             outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER);
@@ -723,11 +741,11 @@
     {
         int offset = 0;
         if (hasUserDataHeader) {
-            int udhLen = userData.payload[0];
-            offset += udhLen;
+            int udhLen = userData.payload[0] & 0x00FF;
+            offset += udhLen + 1;
             byte[] headerData = new byte[udhLen];
             System.arraycopy(userData.payload, 1, headerData, 0, udhLen);
-            userData.userDataHeader = SmsHeader.parse(headerData);
+            userData.userDataHeader = SmsHeader.fromByteArray(headerData);
         }
         switch (userData.msgEncoding) {
         case UserData.ENCODING_OCTET:
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index 02e94ad..7c37bc2 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -93,14 +93,15 @@
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-        builder.append("UserData:\n");
-        builder.append("  msgEncoding: " + (msgEncodingSet ? msgEncoding : "not set") + "\n");
-        builder.append("  msgType: " + msgType + "\n");
-        builder.append("  paddingBits: " + paddingBits + "\n");
-        builder.append("  numFields: " + (int)numFields + "\n");
-        builder.append("  userDataHeader: " + userDataHeader + "\n");
-        builder.append("  payload: '" + HexDump.toHexString(payload) + "'");
-        builder.append(", payloadStr: '" + payloadStr + "'");
+        builder.append("UserData ");
+        builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset"));
+        builder.append(", msgType=" + msgType);
+        builder.append(", paddingBits=" + paddingBits);
+        builder.append(", numFields=" + (int)numFields);
+        builder.append(", userDataHeader=" + userDataHeader);
+        builder.append(", payload='" + HexDump.toHexString(payload) + "'");
+        builder.append(", payloadStr='" + payloadStr + "'");
+        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 4fe1ea0..3459dcd 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -68,6 +68,7 @@
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.PhoneSubInfo;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.gsm.stk.StkService;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.IccVmNotSupportedException;
@@ -204,9 +205,9 @@
             }
         }
 
-        //Change the system setting
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE);
+        //Change the system property
+        SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+                new Integer(RILConstants.GSM_PHONE).toString());
     }
 
     public void dispose() {
@@ -837,21 +838,21 @@
     private void storeVoiceMailNumber(String number) {
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
-        editor.putString(VM_NUMBER, number);        
+        editor.putString(VM_NUMBER, number);
         editor.commit();
         setVmSimImsi(getSubscriberId());
     }
 
     public String getVoiceMailNumber() {
         // Read from the SIM. If its null, try reading from the shared preference area.
-        String number = mSIMRecords.getVoiceMailNumber();        
+        String number = mSIMRecords.getVoiceMailNumber();
         if (TextUtils.isEmpty(number)) {
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
             number = sp.getString(VM_NUMBER, null);
-        }        
+        }
         return number;
     }
-    
+
     private String getVmSimImsi() {
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         return sp.getString(VM_SIM_IMSI, null);
@@ -863,7 +864,7 @@
         editor.putString(VM_SIM_IMSI, imsi);
         editor.commit();
     }
-    
+
     public String getVoiceMailAlphaTag() {
         String ret;
 
@@ -932,13 +933,13 @@
     public void setVoiceMailNumber(String alphaTag,
                             String voiceMailNumber,
                             Message onComplete) {
-        
-        Message resp;        
+
+        Message resp;
         mVmNumber = voiceMailNumber;
         resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
         mSIMRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
     }
-    
+
     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
         switch (commandInterfaceCFReason) {
         case CF_REASON_UNCONDITIONAL:
@@ -1317,11 +1318,11 @@
 
                 case EVENT_SIM_RECORDS_LOADED:
                     updateCurrentCarrierInProvider();
-                    
+
                     // Check if this is a different SIM than the previous one. If so unset the
                     // voice mail number.
                     String imsi = getVmSimImsi();
-                    if (imsi != null && !getSubscriberId().equals(imsi)) {                        
+                    if (imsi != null && !getSubscriberId().equals(imsi)) {
                         storeVoiceMailNumber(null);
                         setVmSimImsi(null);
                     }
@@ -1403,7 +1404,7 @@
                         onComplete.sendToTarget();
                     }
                     break;
-                    
+
                 case EVENT_SET_VM_NUMBER_DONE:
                     ar = (AsyncResult)msg.obj;
                     if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
@@ -1417,7 +1418,7 @@
                     }
                     break;
 
-                    
+
                 case EVENT_GET_CALL_FORWARD_DONE:
                     ar = (AsyncResult)msg.obj;
                     if (ar.exception == null) {
@@ -1460,7 +1461,7 @@
 
     /**
      * Sets the "current" field in the telephony provider according to the SIM's operator
-     * 
+     *
      * @return true for success; false otherwise.
      */
     boolean updateCurrentCarrierInProvider() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 3e73caf..2fce188 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -39,8 +39,11 @@
 final class GsmSMSDispatcher extends SMSDispatcher {
     private static final String TAG = "GSM";
 
+    private GSMPhone mGsmPhone;
+
     GsmSMSDispatcher(GSMPhone phone) {
         super(phone);
+        mGsmPhone = phone;
     }
 
     /**
@@ -97,110 +100,41 @@
 
         // Special case the message waiting indicator messages
         if (sms.isMWISetMessage()) {
-            ((GSMPhone) mPhone).updateMessageWaitingIndicator(true);
-
-            if (sms.isMwiDontStore()) {
-                handled = true;
-            }
-
+            mGsmPhone.updateMessageWaitingIndicator(true);
+            handled |= sms.isMwiDontStore();
             if (Config.LOGD) {
-                Log.d(TAG,
-                        "Received voice mail indicator set SMS shouldStore="
-                         + !handled);
+                Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
             }
         } else if (sms.isMWIClearMessage()) {
-            ((GSMPhone) mPhone).updateMessageWaitingIndicator(false);
-
-            if (sms.isMwiDontStore()) {
-                handled = true;
-            }
-
+            mGsmPhone.updateMessageWaitingIndicator(false);
+            handled |= sms.isMwiDontStore();
             if (Config.LOGD) {
-                Log.d(TAG,
-                        "Received voice mail indicator clear SMS shouldStore="
-                        + !handled);
+                Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
             }
         }
 
-        if (handled) {
-            return;
-        }
+        if (handled) return;
 
-        // Parse the headers to see if this is partial, or port addressed
-        int referenceNumber = -1;
-        int count = 0;
-        int sequence = 0;
-        int destPort = -1;
-
-        SmsHeader header = sms.getUserDataHeader();
-        if (header != null) {
-            for (SmsHeader.Element element : header.getElements()) {
-                try {
-                    switch (element.getID()) {
-                        case SmsHeader.CONCATENATED_8_BIT_REFERENCE: {
-                            byte[] data = element.getData();
-                            
-                            referenceNumber = data[0] & 0xff;
-                            count = data[1] & 0xff;
-                            sequence = data[2] & 0xff;
-                            
-                            // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence
-                            // is zero, or sequence > count, ignore the entire element
-                            if (count == 0 || sequence == 0 || sequence > count) {
-                                referenceNumber = -1;
-                            }
-                            break;
-                        }
-                        
-                        case SmsHeader.CONCATENATED_16_BIT_REFERENCE: {
-                            byte[] data = element.getData();
-                            
-                            referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff);
-                            count = data[2] & 0xff;
-                            sequence = data[3] & 0xff;
-                            
-                            // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence
-                            // is zero, or sequence > count, ignore the entire element
-                            if (count == 0 || sequence == 0 || sequence > count) {
-                                referenceNumber = -1;
-                            }
-                            break;
-                        }
-                        
-                        case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: {
-                            byte[] data = element.getData();
-                            
-                            destPort = (data[0] & 0xff) << 8;
-                            destPort |= (data[1] & 0xff);
-                            
-                            break;
-                        }
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    Log.e(TAG, "Bad element in header", e);
-                    return;  // TODO: NACK the message or something, don't just discard.
-                }
-            }
-        }
-
-        if (referenceNumber == -1) {
-            // notify everyone of the message if it isn't partial
+        SmsHeader smsHeader = sms.getUserDataHeader();
+         // See if message is partial or port addressed.
+        if ((smsHeader == null) || (smsHeader.concatRef == null)) {
+            // Message is not partial (not part of concatenated sequence).
             byte[][] pdus = new byte[1][];
             pdus[0] = sms.getPdu();
 
-            if (destPort != -1) {
-                if (destPort == SmsHeader.PORT_WAP_PUSH) {
+            if (smsHeader.portAddrs != null) {
+                if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
                     mWapPush.dispatchWapPdu(sms.getUserData());
                 }
-                // The message was sent to a port, so concoct a URI for it
-                dispatchPortAddressedPdus(pdus, destPort);
+                // The message was sent to a port, so concoct a URI for it.
+                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
             } else {
-                // It's a normal message, dispatch it
+                // Normal short and non-port-addressed message, dispatch it.
                 dispatchPdus(pdus);
             }
         } else {
-            // Process the message part
-            processMessagePart(sms, referenceNumber, sequence, count, destPort);
+            // Process the message part.
+            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
         }
     }
 
@@ -208,28 +142,30 @@
     protected void sendMultipartText(String destinationAddress, String scAddress,
             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
             ArrayList<PendingIntent> deliveryIntents) {
-        int ref = ++sConcatenatedRef & 0xff;
 
-        for (int i = 0, count = parts.size(); i < count; i++) {
-            // build SmsHeader
-            byte[] data = new byte[3];
-            data[0] = (byte) ref;   // reference #, unique per message
-            data[1] = (byte) count; // total part count
-            data[2] = (byte) (i + 1);  // 1-based sequence
-            SmsHeader header = new SmsHeader();
-            header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
+        int refNumber = getNextConcatenatedRef() & 0x00FF;
+
+        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+            concatRef.refNumber = refNumber;
+            concatRef.seqNumber = i + 1;  // 1-based sequence
+            concatRef.msgCount = msgCount;
+            concatRef.isEightBits = false;
+            SmsHeader smsHeader = new SmsHeader();
+            smsHeader.concatRef = concatRef;
+
             PendingIntent sentIntent = null;
-            PendingIntent deliveryIntent = null;
-
             if (sentIntents != null && sentIntents.size() > i) {
                 sentIntent = sentIntents.get(i);
             }
+
+            PendingIntent deliveryIntent = null;
             if (deliveryIntents != null && deliveryIntents.size() > i) {
                 deliveryIntent = deliveryIntents.get(i);
             }
 
             SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, header.toByteArray());
+                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader));
 
             sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
         }
@@ -259,18 +195,16 @@
      *   to the recipient.  The raw pdu of the status report is in the
      *   extended data ("pdu").
      */
-    private void sendMultipartTextWithPermit(String destinationAddress, 
+    private void sendMultipartTextWithPermit(String destinationAddress,
             String scAddress, ArrayList<String> parts,
-            ArrayList<PendingIntent> sentIntents, 
+            ArrayList<PendingIntent> sentIntents,
             ArrayList<PendingIntent> deliveryIntents) {
-        
-        PendingIntent sentIntent = null;
-        PendingIntent deliveryIntent = null;
-        
+
         // check if in service
         int ss = mPhone.getServiceState().getState();
         if (ss != ServiceState.STATE_IN_SERVICE) {
             for (int i = 0, count = parts.size(); i < count; i++) {
+                PendingIntent sentIntent = null;
                 if (sentIntents != null && sentIntents.size() > i) {
                     sentIntent = sentIntents.get(i);
                 }
@@ -280,26 +214,29 @@
             return;
         }
 
-        int ref = ++sConcatenatedRef & 0xff;
+        int refNumber = getNextConcatenatedRef() & 0x00FF;
 
-        for (int i = 0, count = parts.size(); i < count; i++) {
-            // build SmsHeader
-            byte[] data = new byte[3];
-            data[0] = (byte) ref;   // reference #, unique per message
-            data[1] = (byte) count; // total part count
-            data[2] = (byte) (i + 1);  // 1-based sequence
-            SmsHeader header = new SmsHeader();
-            header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
- 
+        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+            concatRef.refNumber = refNumber;
+            concatRef.seqNumber = i + 1;  // 1-based sequence
+            concatRef.msgCount = msgCount;
+            concatRef.isEightBits = false;
+            SmsHeader smsHeader = new SmsHeader();
+            smsHeader.concatRef = concatRef;
+
+            PendingIntent sentIntent = null;
             if (sentIntents != null && sentIntents.size() > i) {
                 sentIntent = sentIntents.get(i);
             }
+
+            PendingIntent deliveryIntent = null;
             if (deliveryIntents != null && deliveryIntents.size() > i) {
                 deliveryIntent = deliveryIntents.get(i);
             }
 
             SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, header.toByteArray());
+                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader));
 
             HashMap<String, Object> map = new HashMap<String, Object>();
             map.put("smsc", pdus.encodedScAddress);
@@ -307,7 +244,7 @@
 
             SmsTracker tracker =  SmsTrackerFactory(map, sentIntent, deliveryIntent);
             sendSms(tracker);
-        }        
+        }
     }
 
     /** {@inheritDoc} */
@@ -376,4 +313,3 @@
     }
 
 }
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 867b719..ed61c3f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -330,9 +330,20 @@
     public static SubmitPdu getSubmitPdu(String scAddress,
             String destinationAddress, short destinationPort, byte[] data,
             boolean statusReportRequested) {
-        if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) {
+
+        SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
+        portAddrs.destPort = destinationPort;
+        portAddrs.origPort = 0;
+        portAddrs.areEightBits = false;
+
+        SmsHeader smsHeader = new SmsHeader();
+        smsHeader.portAddrs = portAddrs;
+
+        byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader);
+
+        if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) {
             Log.e(LOG_TAG, "SMS data message may only contain "
-                    + (MAX_USER_DATA_BYTES - 7) + " bytes");
+                    + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes");
             return null;
         }
 
@@ -348,21 +359,12 @@
 
         // (no TP-Validity-Period)
 
-        // User data size
-        bo.write(data.length + 7);
+        // Total size
+        bo.write(data.length + smsHeaderData.length + 1);
 
-        // User data header size
-        bo.write(0x06); // header is 6 octets
-
-        // User data header, indicating the destination port
-        bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port
-                                                                // addressing
-                                                                // header
-        bo.write(0x04); // each port is 2 octets
-        bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port
-        bo.write(destinationPort & 0xFF); // LSB of destination port
-        bo.write(0x00); // MSB of originating port
-        bo.write(0x00); // LSB of originating port
+        // User data header
+        bo.write(smsHeaderData.length);
+        bo.write(smsHeaderData, 0, smsHeaderData.length);
 
         // User data
         bo.write(data, 0, data.length);
@@ -562,7 +564,7 @@
 
                 byte[] udh = new byte[userDataHeaderLength];
                 System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength);
-                userDataHeader = SmsHeader.parse(udh);
+                userDataHeader = SmsHeader.fromByteArray(udh);
                 offset += userDataHeaderLength;
 
                 int headerBits = (userDataHeaderLength + 1) * 8;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index b3e88e1..f8d5d4d 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -136,6 +136,81 @@
     }
 
     @SmallTest
+    public void testUserDataHeaderConcatRefFeedback() throws Exception {
+        BearerData bearerData = new BearerData();
+        bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+        bearerData.messageId = 55;
+        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+        concatRef.refNumber = 0xEE;
+        concatRef.msgCount = 2;
+        concatRef.seqNumber = 2;
+        concatRef.isEightBits = true;
+        SmsHeader smsHeader = new SmsHeader();
+        smsHeader.concatRef = concatRef;
+        byte[] encodedHeader = SmsHeader.toByteArray(smsHeader);
+        SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader);
+        assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber);
+        assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount);
+        assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber);
+        assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits);
+        assertEquals(decodedHeader.portAddrs, null);
+        UserData userData = new UserData();
+        userData.payloadStr = "User Data Header (UDH) feedback test";
+        userData.userDataHeader = smsHeader;
+        bearerData.userData = userData;
+        byte[] encodedSms = BearerData.encode(bearerData);
+        BearerData revBearerData = BearerData.decode(encodedSms);
+        decodedHeader = revBearerData.userData.userDataHeader;
+        assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber);
+        assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount);
+        assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber);
+        assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits);
+        assertEquals(decodedHeader.portAddrs, null);
+    }
+
+    @SmallTest
+    public void testUserDataHeaderMixedFeedback() throws Exception {
+        BearerData bearerData = new BearerData();
+        bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+        bearerData.messageId = 42;
+        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+        concatRef.refNumber = 0x34;
+        concatRef.msgCount = 5;
+        concatRef.seqNumber = 2;
+        concatRef.isEightBits = false;
+        SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
+        portAddrs.destPort = 88;
+        portAddrs.origPort = 66;
+        portAddrs.areEightBits = false;
+        SmsHeader smsHeader = new SmsHeader();
+        smsHeader.concatRef = concatRef;
+        smsHeader.portAddrs = portAddrs;
+        byte[] encodedHeader = SmsHeader.toByteArray(smsHeader);
+        SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader);
+        assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber);
+        assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount);
+        assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber);
+        assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits);
+        assertEquals(decodedHeader.portAddrs.destPort, portAddrs.destPort);
+        assertEquals(decodedHeader.portAddrs.origPort, portAddrs.origPort);
+        assertEquals(decodedHeader.portAddrs.areEightBits, portAddrs.areEightBits);
+        UserData userData = new UserData();
+        userData.payloadStr = "User Data Header (UDH) feedback test";
+        userData.userDataHeader = smsHeader;
+        bearerData.userData = userData;
+        byte[] encodedSms = BearerData.encode(bearerData);
+        BearerData revBearerData = BearerData.decode(encodedSms);
+        decodedHeader = revBearerData.userData.userDataHeader;
+        assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber);
+        assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount);
+        assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber);
+        assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits);
+        assertEquals(decodedHeader.portAddrs.destPort, portAddrs.destPort);
+        assertEquals(decodedHeader.portAddrs.origPort, portAddrs.origPort);
+        assertEquals(decodedHeader.portAddrs.areEightBits, portAddrs.areEightBits);
+    }
+
+    @SmallTest
     public void testReplyOption() throws Exception {
         String pdu1 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87450080a0180";
         BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
index 360352b..9d44fd9 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
@@ -69,10 +69,15 @@
 
         SmsHeader header = sms.getUserDataHeader();
         assertNotNull(header);
-
-        Iterator<SmsHeader.Element> elements = header.getElements().iterator();
-        assertNotNull(elements);
-
+        assertNotNull(header.concatRef);
+        assertEquals(header.concatRef.refNumber, 42);
+        assertEquals(header.concatRef.msgCount, 2);
+        assertEquals(header.concatRef.seqNumber, 1);
+        assertEquals(header.concatRef.isEightBits, true);
+        assertNotNull(header.portAddrs);
+        assertEquals(header.portAddrs.destPort, 2948);
+        assertEquals(header.portAddrs.origPort, 9200);
+        assertEquals(header.portAddrs.areEightBits, false);
 
         pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F"
                 + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141"
@@ -81,9 +86,15 @@
 
         header = sms.getUserDataHeader();
         assertNotNull(header);
-
-        elements = header.getElements().iterator();
-        assertNotNull(elements);
+        assertNotNull(header.concatRef);
+        assertEquals(header.concatRef.refNumber, 42);
+        assertEquals(header.concatRef.msgCount, 2);
+        assertEquals(header.concatRef.seqNumber, 2);
+        assertEquals(header.concatRef.isEightBits, true);
+        assertNotNull(header.portAddrs);
+        assertEquals(header.portAddrs.destPort, 2948);
+        assertEquals(header.portAddrs.origPort, 9200);
+        assertEquals(header.portAddrs.areEightBits, false);
 
         /*
         * UCS-2 encoded SMS
diff --git a/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java b/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
index 5df8991..e2336f8 100644
--- a/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
@@ -28,18 +28,20 @@
 
     @SmallTest
     public void test7bitWithHeader() throws Exception {
-        byte[] data = new byte[3];
-        data[0] = (byte) 1;
-        data[1] = (byte) 2;
-        data[2] = (byte) 2;
+        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+        concatRef.refNumber = 1;
+        concatRef.seqNumber = 2;
+        concatRef.msgCount = 2;
+        concatRef.isEightBits = true;
         SmsHeader header = new SmsHeader();
-        header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
+        header.concatRef = concatRef;
 
-        String message = "aaaaaaaaaabbbbbbbbbbcccccccccc"; 
-        byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header.toByteArray());
+        String message = "aaaaaaaaaabbbbbbbbbbcccccccccc";
+        byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message,
+                SmsHeader.toByteArray(header));
         int septetCount = GsmAlphabet.countGsmSeptets(message, false);
         String parsedMessage = GsmAlphabet.gsm7BitPackedToString(
-                userData, header.toByteArray().length+1, septetCount, 1);
+                userData, SmsHeader.toByteArray(header).length+1, septetCount, 1);
         assertEquals(message, parsedMessage);
     }
 
@@ -306,4 +308,3 @@
                 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
     }
 }
-
diff --git a/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java b/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java
index 5d5d1f9..8a66614 100644
--- a/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java
@@ -34,35 +34,38 @@
     public void testCMT1() throws Exception {
         SmsMessage sms;
         SmsHeader header;
-        Iterator<SmsHeader.Element> elements;
 
         String[] lines = new String[2];
-        
-        lines[0] = "+CMT: ,158";             
+
+        lines[0] = "+CMT: ,158";
         lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B"
                  + "8423F000035502010106276170706C69636174696F6E2F766E642E776170"
                  + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F"
                  + "7547514D4141424C3641414141536741415A4B554141414141008D908918"
                  + "802B31363530323438363137392F545950453D504C4D4E008A808E028000"
                  + "88058103093A8083687474703A2F2F36";
-             
+
         sms = SmsMessage.newFromCMT(lines);
         header = sms.getUserDataHeader();
         assertNotNull(header);
         assertNotNull(sms.getUserData());
-                    
-        elements = header.getElements().iterator();
-        assertNotNull(elements);
+        assertNotNull(header.concatRef);
+        assertEquals(header.concatRef.refNumber, 85);
+        assertEquals(header.concatRef.msgCount, 2);
+        assertEquals(header.concatRef.seqNumber, 1);
+        assertEquals(header.concatRef.isEightBits, true);
+        assertNotNull(header.portAddrs);
+        assertEquals(header.portAddrs.destPort, 2948);
+        assertEquals(header.portAddrs.origPort, 9200);
+        assertEquals(header.portAddrs.areEightBits, false);
     }
-    
+
     @MediumTest
     public void testCMT2() throws Exception {
         SmsMessage sms;
         SmsHeader header;
-        Iterator<SmsHeader.Element> elements;
 
         String[] lines = new String[2];
-        
 
         lines[0] = "+CMT: ,77";
         lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F"
@@ -71,12 +74,17 @@
 
         sms = SmsMessage.newFromCMT(lines);
         header = sms.getUserDataHeader();
-        System.out.println("header = " + header);
         assertNotNull(header);
         assertNotNull(sms.getUserData());
-                    
-        elements = header.getElements().iterator();
-        assertNotNull(elements);
+        assertNotNull(header.concatRef);
+        assertEquals(header.concatRef.refNumber, 85);
+        assertEquals(header.concatRef.msgCount, 2);
+        assertEquals(header.concatRef.seqNumber, 2);
+        assertEquals(header.concatRef.isEightBits, true);
+        assertNotNull(header.portAddrs);
+        assertEquals(header.portAddrs.destPort, 2948);
+        assertEquals(header.portAddrs.origPort, 9200);
+        assertEquals(header.portAddrs.areEightBits, false);
     }
 
     @MediumTest