auto import from //branches/cupcake_rel/...@141571
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index b14e5fd..05de829 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -143,7 +143,20 @@
                         "   (SELECT pdu.thread_id FROM part JOIN pdu ON pdu._id=part.mid " +
                         "     WHERE part._id=new._id LIMIT 1); " +
                         " END";
-    
+
+    // When the 'mid' column in the part table is updated, we need to run the trigger to update
+    // the threads table's has_attachment column, if the part is an attachment.
+    private static final String PART_UPDATE_THREADS_ON_UPDATE_TRIGGER =
+                        "CREATE TRIGGER update_threads_on_update_part " +
+                        " AFTER UPDATE of " + Part.MSG_ID + " ON part " +
+                        " WHEN new.ct != 'text/plain' AND new.ct != 'application/smil' " +
+                        " BEGIN " +
+                        "  UPDATE threads SET has_attachment=1 WHERE _id IN " +
+                        "   (SELECT pdu.thread_id FROM part JOIN pdu ON pdu._id=part.mid " +
+                        "     WHERE part._id=new._id LIMIT 1); " +
+                        " END";
+
+
     // When a part is deleted (with the same non-text/SMIL constraint as when
     // we set has_attachment), update the threads table for all threads.
     // Unfortunately we cannot update only the thread that the part was
@@ -167,7 +180,7 @@
     private static MmsSmsDatabaseHelper mInstance = null;
 
     static final String DATABASE_NAME = "mmssms.db";
-    static final int DATABASE_VERSION = 43;
+    static final int DATABASE_VERSION = 44;
 
     private MmsSmsDatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -395,6 +408,7 @@
         // Update threads table to indicate whether attachments exist when
         // parts are inserted or deleted.
         db.execSQL(PART_UPDATE_THREADS_ON_INSERT_TRIGGER);
+        db.execSQL(PART_UPDATE_THREADS_ON_UPDATE_TRIGGER);
         db.execSQL(PART_UPDATE_THREADS_ON_DELETE_TRIGGER);
     }
 
@@ -751,6 +765,22 @@
             } finally {
                 db.endTransaction();
             }
+            // fall through
+        case 43:
+            if (currentVersion <= 43) {
+                return;
+            }
+
+            db.beginTransaction();
+            try {
+                upgradeDatabaseToVersion44(db);
+                db.setTransactionSuccessful();
+            } catch (Throwable ex) {
+                Log.e(TAG, ex.getMessage(), ex);
+                break;
+            } finally {
+                db.endTransaction();
+            }
             return;
         }
 
@@ -813,4 +843,16 @@
         db.execSQL(PART_UPDATE_THREADS_ON_INSERT_TRIGGER);
         db.execSQL(PART_UPDATE_THREADS_ON_DELETE_TRIGGER);
     }
+
+    private void upgradeDatabaseToVersion44(SQLiteDatabase db) {
+        // Set the values of that column correctly based on the current
+        // contents of the database.
+        db.execSQL("UPDATE threads SET has_attachment=1 WHERE _id IN " +
+                   "  (SELECT DISTINCT pdu.thread_id FROM part " +
+                   "   JOIN pdu ON pdu._id=part.mid " +
+                   "   WHERE part.ct != 'text/plain' AND part.ct != 'application/smil')");
+
+        // add the update trigger for keeping the threads up to date.
+        db.execSQL(PART_UPDATE_THREADS_ON_UPDATE_TRIGGER);
+    }
 }
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 324d007..59c046f 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -26,6 +26,7 @@
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.os.Environment;
+import android.preference.PreferenceManager;
 import android.provider.Telephony;
 import android.util.Config;
 import android.util.Log;
@@ -49,9 +50,14 @@
     private static final int URL_CURRENT = 2;
     private static final int URL_ID = 3;
     private static final int URL_RESTOREAPN = 4;
+    private static final int URL_PREFERAPN = 5;
 
     private static final String TAG = "TelephonyProvider";
     private static final String CARRIERS_TABLE = "carriers";
+
+    private static final String PREF_FILE = "preferred-apn";
+    private static final String COLUMN_APN_ID = "apn_id";
+
     private static final String PARTNER_APNS_PATH = "etc/apns-conf.xml";
 
     private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
@@ -64,6 +70,7 @@
         s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT);
         s_urlMatcher.addURI("telephony", "carriers/#", URL_ID);
         s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN);
+        s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN);
 
         s_currentNullMap = new ContentValues(1);
         s_currentNullMap.put("current", (Long) null);
@@ -137,7 +144,7 @@
                 publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
                 loadApns(db, parser);
             } catch (Exception e) {
-                Log.e(TAG, "Got execption while loading APN database.", e);
+                Log.e(TAG, "Got exception while loading APN database.", e);
             } finally {
                 parser.close();
             }
@@ -263,6 +270,18 @@
         return true;
     }
 
+    private void setPreferredApnId(Long id) {
+        SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+        SharedPreferences.Editor editor = sp.edit();
+        editor.putLong(COLUMN_APN_ID, id != null ? id.longValue() : -1);        
+        editor.commit();
+    }
+
+    private long getPreferredApnId() {
+        SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+        return sp.getLong(COLUMN_APN_ID, -1);
+    }
+
     @Override
     public Cursor query(Uri url, String[] projectionIn, String selection,
             String[] selectionArgs, String sort) {
@@ -279,6 +298,8 @@
 
             case URL_CURRENT: {
                 qb.appendWhere("current IS NOT NULL");
+                // ignore the selection
+                selection = null;
                 break;
             }
 
@@ -287,6 +308,11 @@
                 break;
             }
 
+            case URL_PREFERAPN: {
+                qb.appendWhere("_id = " + getPreferredApnId());
+                break;
+            }
+
             default: {
                 return null;
             }
@@ -308,6 +334,9 @@
         case URL_ID:
             return "vnd.android.cursor.item/telephony-carrier";
 
+        case URL_PREFERAPN:
+            return "vnd.android.cursor.item/telephony-carrier";
+
         default:
             throw new IllegalArgumentException("Unknown URL " + url);
         }
@@ -396,6 +425,16 @@
                 }
                 break;
             }
+
+            case URL_PREFERAPN:
+            {
+                if (initialValues != null) {
+                    if(initialValues.containsKey(COLUMN_APN_ID)) {
+                        setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID));
+                    }
+                }
+                break;
+            }
         }
 
         if (notify) {
@@ -441,6 +480,13 @@
                 break;
             }
 
+            case URL_PREFERAPN:
+            {
+                setPreferredApnId((long)-1);
+                count = 1;
+                break;
+            }
+
             default: {
                 throw new UnsupportedOperationException("Cannot delete that URL: " + url);
             }
@@ -456,7 +502,7 @@
     @Override
     public int update(Uri url, ContentValues values, String where, String[] whereArgs)
     {
-        int count;
+        int count = 0;
 
         checkPermission();
 
@@ -487,6 +533,17 @@
                 break;
             }
 
+            case URL_PREFERAPN:
+            {
+                if (values != null) {
+                    if (values.containsKey(COLUMN_APN_ID)) {
+                        setPreferredApnId(values.getAsLong(COLUMN_APN_ID));
+                        count = 1;
+                    }
+                }
+                break;
+            }
+
             default: {
                 throw new UnsupportedOperationException("Cannot update that URL: " + url);
             }
@@ -511,6 +568,7 @@
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
 
         db.delete(CARRIERS_TABLE, null, null);
+        setPreferredApnId((long)-1);
         ((DatabaseHelper) mOpenHelper).initDatabase(db);
     }
 }