auto import from //depot/cupcake/@137055
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dfbf918..c1af548 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -29,7 +29,9 @@
             android:writePermission="android.permission.WRITE_SMS" />
         <provider android:name="MmsProvider" android:authorities="mms" android:multiprocess="true" 
             android:readPermission="android.permission.READ_SMS"
-            android:writePermission="android.permission.WRITE_SMS" />
+            android:writePermission="android.permission.WRITE_SMS">
+            <grant-uri-permission android:pathPrefix="/part/" />
+        </provider>
         <provider android:name="MmsSmsProvider" android:authorities="mms-sms" android:multiprocess="true" 
             android:readPermission="android.permission.READ_SMS"
             android:writePermission="android.permission.WRITE_SMS" />
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 1644186..31d7cb7 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -230,6 +230,10 @@
             }
             c.close();
         }
+        // remove orphaned threads
+        db.delete("threads",
+                "_id NOT IN (SELECT DISTINCT thread_id FROM sms " +
+                "UNION SELECT DISTINCT thread_id FROM pdu)", null);
     }
     
     public static int deleteOneSms(SQLiteDatabase db, int message_id) {
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index 56b39de..ee60142 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -46,7 +46,9 @@
     private static final Uri NOTIFICATION_URI = Uri.parse("content://sms");
     private static final Uri SIM_URI = Uri.parse("content://sms/sim");
     static final String TABLE_SMS = "sms";
-
+    private static final String TABLE_RAW = "raw";
+    private static final String TABLE_SR_PENDING = "sr_pending";
+    
     private static final Integer ONE = Integer.valueOf(1);
 
     /**
@@ -244,7 +246,12 @@
             ArrayList<SmsMessage> messages = smsManager.getAllMessagesFromSim();
             ArrayList<ArrayList> singleRow = new ArrayList<ArrayList>();
 
-            singleRow.add(convertSimToSms(messages.get(messageIndex)));
+            SmsMessage message = messages.get(messageIndex);
+            if (message == null) {
+                throw new IllegalArgumentException(
+                        "Message not retrieved. ID: " + messageIndexString);
+            }
+            singleRow.add(convertSimToSms(message));
             return withSimNotificationUri(
                     new ArrayListCursor(SIM_COLUMNS, singleRow));
         } catch (NumberFormatException exception) {
@@ -262,7 +269,10 @@
         ArrayList<ArrayList> rows = new ArrayList<ArrayList>();
 
         for (int count = messages.size(), i = 0; i < count; i++) {
-            rows.add(convertSimToSms(messages.get(i)));
+            SmsMessage message = messages.get(i);
+            if (message != null) {
+                rows.add(convertSimToSms(message));
+            }
         }
         return withSimNotificationUri(new ArrayListCursor(SIM_COLUMNS, rows));
     }
@@ -552,14 +562,17 @@
     public int update(
             Uri url, ContentValues values, String where, String[] whereArgs) {
         int count = 0;
+        String table = TABLE_SMS;
+        String extraWhere = null;
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
         switch (sURLMatcher.match(url)) {
             case SMS_RAW_MESSAGE:
-                count = db.update("raw", values, where, whereArgs);
+                table = TABLE_RAW;
                 break;
 
             case SMS_STATUS_PENDING:
-                count = db.update("sr_pending", values, where, whereArgs);
+                table = TABLE_SR_PENDING;
                 break;
 
             case SMS_ALL:
@@ -570,17 +583,10 @@
             case SMS_DRAFT:
             case SMS_OUTBOX:
             case SMS_CONVERSATIONS:
-                count = db.update(
-                        TABLE_SMS, values, where, whereArgs);
                 break;
 
             case SMS_ALL_ID:
-                if (where != null) {
-                    throw new UnsupportedOperationException(
-                            "WHERE not supported");
-                }
-                count = db.update(TABLE_SMS, values, "_id="
-                        + url.getPathSegments().get(0), null);
+                extraWhere = "_id=" + url.getPathSegments().get(0);
                 break;
 
             case SMS_INBOX_ID:
@@ -588,40 +594,25 @@
             case SMS_SENT_ID:
             case SMS_DRAFT_ID:
             case SMS_OUTBOX_ID:
-                if (where != null) {
-                    throw new UnsupportedOperationException(
-                            "WHERE not supported for this URI");
-                }
-                count = db.update(TABLE_SMS, values, "_id="
-                        + url.getPathSegments().get(1), null);
+                extraWhere = "_id=" + url.getPathSegments().get(1);
                 break;
 
             case SMS_CONVERSATIONS_ID: {
-                int threadId;
+                String threadId = url.getPathSegments().get(1);
 
                 try {
-                    threadId = Integer.parseInt(url.getPathSegments().get(1));
+                    Integer.parseInt(threadId);
                 } catch (Exception ex) {
-                    Log.e(TAG, "Bad conversation thread id: "
-                            + url.getPathSegments().get(1));
-                    count = 0;
+                    Log.e(TAG, "Bad conversation thread id: " + threadId);
                     break;
                 }
 
-                if (where != null) {
-                    throw new UnsupportedOperationException(
-                            "WHERE not supported for this URI");
-                }
-                count = db.update(
-                        TABLE_SMS, values, "thread_id = " + threadId,
-                        null);
+                extraWhere = "thread_id=" + threadId;
                 break;
             }
 
             case SMS_STATUS_ID:
-                String idString = url.getPathSegments().get(1); 
-
-                count = db.update(TABLE_SMS, values, "_id=" + idString, null);
+                extraWhere = "_id=" + url.getPathSegments().get(1);
                 break;  
                     
             default:
@@ -629,6 +620,9 @@
                         "URI " + url + " not supported");
         }
 
+        where = DatabaseUtils.concatenateWhere(where, extraWhere);
+        count = db.update(table, values, where, whereArgs);
+
         if (count > 0) {
             notifyChange(url);
         }
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 95018be..324d007 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -48,6 +48,7 @@
     private static final int URL_TELEPHONY = 1;
     private static final int URL_CURRENT = 2;
     private static final int URL_ID = 3;
+    private static final int URL_RESTOREAPN = 4;
 
     private static final String TAG = "TelephonyProvider";
     private static final String CARRIERS_TABLE = "carriers";
@@ -62,6 +63,7 @@
         s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY);
         s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT);
         s_urlMatcher.addURI("telephony", "carriers/#", URL_ID);
+        s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN);
 
         s_currentNullMap = new ContentValues(1);
         s_currentNullMap.put("current", (Long) null);
@@ -122,6 +124,10 @@
                     "type TEXT," +
                     "current INTEGER);");
 
+            initDatabase(db);
+        }
+
+        private void initDatabase(SQLiteDatabase db) {
             // Read internal APNS data
             Resources r = mContext.getResources();
             XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
@@ -429,6 +435,12 @@
                 break;
             }
 
+            case URL_RESTOREAPN: {
+                count = 1;
+                restoreDefaultAPN();
+                break;
+            }
+
             default: {
                 throw new UnsupportedOperationException("Cannot delete that URL: " + url);
             }
@@ -474,7 +486,7 @@
                         new String[] { url.getLastPathSegment() });
                 break;
             }
-            
+
             default: {
                 throw new UnsupportedOperationException("Cannot update that URL: " + url);
             }
@@ -494,4 +506,11 @@
     }
 
     private SQLiteOpenHelper mOpenHelper;
+
+    private void restoreDefaultAPN() {
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
+        db.delete(CARRIERS_TABLE, null, null);
+        ((DatabaseHelper) mOpenHelper).initDatabase(db);
+    }
 }