Merge change Ia75da053 into eclair

* changes:
  Remove DEBUG-only logging in metadata backup agent
diff --git a/api/current.xml b/api/current.xml
index 74f04ab..7dd8b73 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -59234,46 +59234,6 @@
 <parameter name="end" type="int">
 </parameter>
 </method>
-<method name="native_breakText"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="text" type="char[]">
-</parameter>
-<parameter name="index" type="int">
-</parameter>
-<parameter name="count" type="int">
-</parameter>
-<parameter name="maxWidth" type="float">
-</parameter>
-<parameter name="measuredWidth" type="float[]">
-</parameter>
-</method>
-<method name="native_breakText"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="text" type="java.lang.String">
-</parameter>
-<parameter name="measureForwards" type="boolean">
-</parameter>
-<parameter name="maxWidth" type="float">
-</parameter>
-<parameter name="measuredWidth" type="float[]">
-</parameter>
-</method>
 <method name="reset"
  return="void"
  abstract="false"
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 2d2e75f..3b39ae43 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -102,6 +102,7 @@
     private static final String ACCOUNTS_ID = "_id";
     private static final String ACCOUNTS_NAME = "name";
     private static final String ACCOUNTS_TYPE = "type";
+    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
     private static final String ACCOUNTS_PASSWORD = "password";
 
     private static final String TABLE_AUTHTOKENS = "authtokens";
@@ -127,6 +128,8 @@
 
     private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
             new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
+    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
+            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
     private static final Intent ACCOUNTS_CHANGED_INTENT;
 
     private static final String COUNT_OF_MATCHING_GRANTS = ""
@@ -1455,18 +1458,54 @@
         return asBinder();
     }
 
-    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
-        synchronized (mSessions) {
-            final long now = SystemClock.elapsedRealtime();
-            fout.println("AccountManagerService: " + mSessions.size() + " sessions");
-            for (Session session : mSessions.values()) {
-                fout.println("  " + session.toDebugString(now));
+    /**
+     * Searches array of arguments for the specified string
+     * @param args array of argument strings
+     * @param value value to search for
+     * @return true if the value is contained in the array
+     */
+    private static boolean scanArgs(String[] args, String value) {
+        if (args != null) {
+            for (String arg : args) {
+                if (value.equals(arg)) {
+                    return true;
+                }
             }
         }
+        return false;
+    }
 
-        fout.println();
+    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
 
-        mAuthenticatorCache.dump(fd, fout, args);
+        if (isCheckinRequest) {
+            // This is a checkin request. *Only* upload the account types and the count of each.
+            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+
+            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
+                    null, null, ACCOUNTS_TYPE, null, null);
+            try {
+                while (cursor.moveToNext()) {
+                    // print type,count
+                    fout.println(cursor.getString(0) + "," + cursor.getString(1));
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+        } else {
+            synchronized (mSessions) {
+                final long now = SystemClock.elapsedRealtime();
+                fout.println("AccountManagerService: " + mSessions.size() + " sessions");
+                for (Session session : mSessions.values()) {
+                    fout.println("  " + session.toDebugString(now));
+                }
+            }
+
+            fout.println();
+            mAuthenticatorCache.dump(fd, fout, args);
+        }
     }
 
     private void doNotification(Account account, CharSequence message, Intent intent) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index e425f3a..f621483 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -54,7 +54,8 @@
  */
 public class SQLiteDatabase extends SQLiteClosable {
     private static final String TAG = "Database";
-    private static final int DB_OPERATION_EVENT = 52000;
+    private static final int EVENT_DB_OPERATION = 52000;
+    private static final int EVENT_DB_CORRUPT = 75004;
 
     /**
      * Algorithms used in ON CONFLICT clause
@@ -739,6 +740,7 @@
             // Try to recover from this, if we can.
             // TODO: should we do this for other open failures?
             Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
+            EventLog.writeEvent(EVENT_DB_CORRUPT, path);
             new File(path).delete();
             return new SQLiteDatabase(path, factory, flags);
         }
@@ -1732,7 +1734,7 @@
     }
 
     /* package */ void logTimeStat(boolean read, long begin, long end) {
-        EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
+        EventLog.writeEvent(EVENT_DB_OPERATION, mPath, read ? 0 : 1, end - begin);
     }
 
     /**
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
index 35224c7..915f09e 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -1051,8 +1051,8 @@
             List<String> nameList;
             switch (VCardConfig.getNameOrderType(mVCardType)) {
             case VCardConfig.NAME_ORDER_JAPANESE:
-                if (VCardUtils.containsOnlyAscii(mFamilyName) &&
-                        VCardUtils.containsOnlyAscii(mGivenName)) {
+                if (VCardUtils.containsOnlyPrintableAscii(mFamilyName) &&
+                        VCardUtils.containsOnlyPrintableAscii(mGivenName)) {
                     nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix);
                 } else {
                     nameList = Arrays.asList(mPrefix, mFamilyName, mMiddleName, mGivenName, mSuffix);
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 40b4fc4..b0376c4 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -56,8 +56,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * <p>
@@ -234,9 +236,8 @@
     private static final String VCARD_PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
 
     // Android specific properties
-    private static final String VCARD_PROPERTY_X_PHONETIC_NAME = "X-PHONETIC-NAME";
+    // TODO: ues extra MIME-TYPE instead of adding this kind of inflexible fields
     private static final String VCARD_PROPERTY_X_NICKNAME = "X-NICKNAME";
-    // TODO: add properties like X-LATITUDE
 
     // Property for call log entry
     private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME";
@@ -396,7 +397,7 @@
         }
 
         boolean needCharset = false;
-        if (!(VCardUtils.containsOnlyAscii(phoneName))) {
+        if (!(VCardUtils.containsOnlyPrintableAscii(phoneName))) {
             needCharset = true;
         }
         appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, phoneName, needCharset, false);
@@ -596,7 +597,7 @@
         if (TextUtils.isEmpty(name)) {
             name = mCursor.getString(NUMBER_COLUMN_INDEX);
         }
-        final boolean needCharset = !(VCardUtils.containsOnlyAscii(name));
+        final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name));
         appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, name, needCharset, false);
         appendVCardLine(builder, VCARD_PROPERTY_NAME, name, needCharset, false);
 
@@ -740,213 +741,220 @@
             final Map<String, List<ContentValues>> contentValuesListMap) {
         final List<ContentValues> contentValuesList = contentValuesListMap
                 .get(StructuredName.CONTENT_ITEM_TYPE);
-        if (contentValuesList != null) {
+        if (contentValuesList != null && contentValuesList.size() > 0) {
             appendStructuredNamesInternal(builder, contentValuesList);
         } else if (mIsDoCoMo) {
             appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+        } else if (mIsV30) {
+            // vCard 3.0 requires "N" and "FN" properties.
+            appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+            appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, "");
         }
     }
 
     private void appendStructuredNamesInternal(final StringBuilder builder,
             final List<ContentValues> contentValuesList) {
+        // For safety, we'll emit just one value around StructuredName, as external importers
+        // may get confused with multiple "N", "FN", etc. properties, though it is valid in
+        // vCard spec.
+        ContentValues primaryContentValues = null;
         for (ContentValues contentValues : contentValuesList) {
-            final String familyName = contentValues
-                    .getAsString(StructuredName.FAMILY_NAME);
-            final String middleName = contentValues
-                    .getAsString(StructuredName.MIDDLE_NAME);
-            final String givenName = contentValues
-                    .getAsString(StructuredName.GIVEN_NAME);
-            final String prefix = contentValues
-                    .getAsString(StructuredName.PREFIX);
-            final String suffix = contentValues
-                    .getAsString(StructuredName.SUFFIX);
-            final String displayName = contentValues
-                    .getAsString(StructuredName.DISPLAY_NAME);
+            Integer isSuperPrimary = contentValues.getAsInteger(StructuredName.IS_SUPER_PRIMARY);
+            if (isSuperPrimary != null && isSuperPrimary != 0) {
+                // We choose "super primary" ContentValues.
+                primaryContentValues = contentValues;
+                break;
+            } else if (primaryContentValues == null && contentValues != null) {
+                // We choose the first ContentValues if "super primary" ContentValues does not exist.
+                primaryContentValues = contentValues;
+            }
+        }
 
-            // For now, some primary element is not encoded into Quoted-Printable, which is not
-            // valid in vCard spec strictly. In the future, we may have to have some flag to
-            // enable composer to encode these primary field into Quoted-Printable.
-            if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
-                final String encodedFamily = escapeCharacters(familyName);
-                final String encodedGiven = escapeCharacters(givenName);
-                final String encodedMiddle = escapeCharacters(middleName);
-                final String encodedPrefix = escapeCharacters(prefix);
-                final String encodedSuffix = escapeCharacters(suffix);
+        if (primaryContentValues == null) {
+            Log.e(LOG_TAG, "All ContentValues given from database is empty.");
+            primaryContentValues = new ContentValues();
+        }
 
-                // N property. This order is specified by vCard spec and does not depend on countries.
-                builder.append(VCARD_PROPERTY_NAME);
-                if (!(VCardUtils.containsOnlyAscii(familyName) &&
-                        VCardUtils.containsOnlyAscii(givenName) &&
-                        VCardUtils.containsOnlyAscii(middleName) &&
-                        VCardUtils.containsOnlyAscii(prefix) &&
-                        VCardUtils.containsOnlyAscii(suffix))) {
-                    builder.append(VCARD_ATTR_SEPARATOR);
-                    builder.append(mVCardAttributeCharset);
-                }
+        final String familyName = primaryContentValues
+                .getAsString(StructuredName.FAMILY_NAME);
+        final String middleName = primaryContentValues
+                .getAsString(StructuredName.MIDDLE_NAME);
+        final String givenName = primaryContentValues
+                .getAsString(StructuredName.GIVEN_NAME);
+        final String prefix = primaryContentValues
+                .getAsString(StructuredName.PREFIX);
+        final String suffix = primaryContentValues
+                .getAsString(StructuredName.SUFFIX);
+        final String displayName = primaryContentValues
+                .getAsString(StructuredName.DISPLAY_NAME);
 
-                builder.append(VCARD_DATA_SEPARATOR);
-                builder.append(encodedFamily);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(encodedGiven);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(encodedMiddle);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(encodedPrefix);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(encodedSuffix);
-                builder.append(VCARD_COL_SEPARATOR);
+        // For now, some primary element is not encoded into Quoted-Printable, which is not
+        // valid in vCard spec strictly. In the future, we may have to have some flag to
+        // enable composer to encode these primary field into Quoted-Printable.
+        if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
+            final String encodedFamily = escapeCharacters(familyName);
+            final String encodedGiven = escapeCharacters(givenName);
+            final String encodedMiddle = escapeCharacters(middleName);
+            final String encodedPrefix = escapeCharacters(prefix);
+            final String encodedSuffix = escapeCharacters(suffix);
 
-                final String encodedFullname = VCardUtils.constructNameFromElements(
-                        VCardConfig.getNameOrderType(mVCardType),
-                        encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix);
-
-                // FN property
-                builder.append(VCARD_PROPERTY_FULL_NAME);
-                if (!VCardUtils.containsOnlyAscii(encodedFullname)) {
-                    builder.append(VCARD_ATTR_SEPARATOR);
-                    builder.append(mVCardAttributeCharset);
-                }
-                builder.append(VCARD_DATA_SEPARATOR);
-                builder.append(encodedFullname);
-                builder.append(VCARD_COL_SEPARATOR);
-            } else if (!TextUtils.isEmpty(displayName)) {
-                builder.append(VCARD_PROPERTY_NAME);
+            // N property. This order is specified by vCard spec and does not depend on countries.
+            builder.append(VCARD_PROPERTY_NAME);
+            if (!(VCardUtils.containsOnlyPrintableAscii(familyName) &&
+                    VCardUtils.containsOnlyPrintableAscii(givenName) &&
+                    VCardUtils.containsOnlyPrintableAscii(middleName) &&
+                    VCardUtils.containsOnlyPrintableAscii(prefix) &&
+                    VCardUtils.containsOnlyPrintableAscii(suffix))) {
                 builder.append(VCARD_ATTR_SEPARATOR);
                 builder.append(mVCardAttributeCharset);
-                builder.append(VCARD_DATA_SEPARATOR);
-                builder.append(escapeCharacters(displayName));
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(VCARD_ITEM_SEPARATOR);
-                builder.append(VCARD_COL_SEPARATOR);
-            } else if (mIsDoCoMo) {
-                appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
             }
 
-            String phoneticFamilyName = contentValues
-                    .getAsString(StructuredName.PHONETIC_FAMILY_NAME);
-            String phoneticMiddleName = contentValues
-                    .getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
-            String phoneticGivenName = contentValues
-                    .getAsString(StructuredName.PHONETIC_GIVEN_NAME);
-            if (!(TextUtils.isEmpty(phoneticFamilyName)
-                    && TextUtils.isEmpty(phoneticMiddleName) && TextUtils
-                    .isEmpty(phoneticGivenName))) { // if not empty
-                if (mIsJapaneseMobilePhone) {
-                    phoneticFamilyName = VCardUtils
-                            .toHalfWidthString(phoneticFamilyName);
-                    phoneticMiddleName = VCardUtils
-                            .toHalfWidthString(phoneticMiddleName);
-                    phoneticGivenName = VCardUtils
-                            .toHalfWidthString(phoneticGivenName);
-                }
+            builder.append(VCARD_DATA_SEPARATOR);
+            builder.append(encodedFamily);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(encodedGiven);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(encodedMiddle);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(encodedPrefix);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(encodedSuffix);
+            builder.append(VCARD_COL_SEPARATOR);
 
-                if (mIsV30) {
-                    final String sortString = VCardUtils
-                            .constructNameFromElements(mVCardType,
-                                    phoneticFamilyName, phoneticMiddleName,
-                                    phoneticGivenName);
-                    builder.append(VCARD_PROPERTY_SORT_STRING);
+            final String encodedFullname = VCardUtils.constructNameFromElements(
+                    VCardConfig.getNameOrderType(mVCardType),
+                    encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix);
 
-                    if (!VCardUtils.containsOnlyAscii(sortString)) {
-                        // Strictly, adding charset information is NOT valid in
-                        // VCard 3.0,
-                        // but we'll add this info since parser side may be able to
-                        // use the charset via
-                        // this attribute field.
-                        //
-                        // e.g. Japanese mobile phones use Shift_Jis while RFC 2426
-                        // recommends
-                        // UTF-8. By adding this field, parsers may be able to know
-                        // this text
-                        // is NOT UTF-8 but Shift_Jis.
-                        builder.append(VCARD_ATTR_SEPARATOR);
-                        builder.append(mVCardAttributeCharset);
-                    }
+            // FN property
+            builder.append(VCARD_PROPERTY_FULL_NAME);
+            if (!VCardUtils.containsOnlyPrintableAscii(encodedFullname)) {
+                builder.append(VCARD_ATTR_SEPARATOR);
+                builder.append(mVCardAttributeCharset);
+            }
+            builder.append(VCARD_DATA_SEPARATOR);
+            builder.append(encodedFullname);
+            builder.append(VCARD_COL_SEPARATOR);
+        } else if (!TextUtils.isEmpty(displayName)) {
+            builder.append(VCARD_PROPERTY_NAME);
+            builder.append(VCARD_ATTR_SEPARATOR);
+            builder.append(mVCardAttributeCharset);
+            builder.append(VCARD_DATA_SEPARATOR);
+            builder.append(escapeCharacters(displayName));
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_COL_SEPARATOR);
+        } else if (mIsDoCoMo) {
+            appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+        } else if (mIsV30) {
+            appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+            appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, "");
+        }
 
-                    builder.append(VCARD_DATA_SEPARATOR);
-                    builder.append(sortString);
-                    builder.append(VCARD_COL_SEPARATOR);
-                } else {
-                    // Note: There is no appropriate property for expressing
-                    // phonetic name in
-                    // VCard 2.1, while there is in VCard 3.0 (SORT-STRING).
-                    // We chose to use DoCoMo's way since it is supported by a
-                    // lot of
-                    // Japanese mobile phones.
+        String phoneticFamilyName = primaryContentValues
+                .getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+        String phoneticMiddleName = primaryContentValues
+                .getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+        String phoneticGivenName = primaryContentValues
+                .getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+        if (!(TextUtils.isEmpty(phoneticFamilyName)
+                && TextUtils.isEmpty(phoneticMiddleName) &&
+                TextUtils.isEmpty(phoneticGivenName))) { // if not empty
+            if (mIsJapaneseMobilePhone) {
+                phoneticFamilyName = VCardUtils
+                        .toHalfWidthString(phoneticFamilyName);
+                phoneticMiddleName = VCardUtils
+                        .toHalfWidthString(phoneticMiddleName);
+                phoneticGivenName = VCardUtils
+                        .toHalfWidthString(phoneticGivenName);
+            }
+
+            if (mIsV30) {
+                final String sortString = VCardUtils
+                        .constructNameFromElements(mVCardType,
+                                phoneticFamilyName, phoneticMiddleName,
+                                phoneticGivenName);
+                builder.append(VCARD_PROPERTY_SORT_STRING);
+
+                if (!VCardUtils.containsOnlyPrintableAscii(sortString)) {
+                    // Strictly, adding charset information is NOT valid in
+                    // VCard 3.0,
+                    // but we'll add this info since parser side may be able to
+                    // use the charset via
+                    // this attribute field.
                     //
-                    // TODO: should use Quoted-Pritable?
-                    builder.append(VCARD_PROPERTY_SOUND);
+                    // e.g. Japanese mobile phones use Shift_Jis while RFC 2426
+                    // recommends
+                    // UTF-8. By adding this field, parsers may be able to know
+                    // this text
+                    // is NOT UTF-8 but Shift_Jis.
                     builder.append(VCARD_ATTR_SEPARATOR);
-                    builder.append(Constants.ATTR_TYPE_X_IRMC_N);
-                    builder.append(VCARD_ATTR_SEPARATOR);
-
-                    if (!(VCardUtils.containsOnlyAscii(phoneticFamilyName) &&
-                            VCardUtils.containsOnlyAscii(phoneticMiddleName) &&
-                            VCardUtils.containsOnlyAscii(phoneticGivenName))) {
-                        builder.append(mVCardAttributeCharset);
-                        builder.append(VCARD_DATA_SEPARATOR);
-                    }
-
-                    builder.append(escapeCharacters(phoneticFamilyName));
-                    builder.append(VCARD_ITEM_SEPARATOR);
-                    builder.append(escapeCharacters(phoneticMiddleName));
-                    builder.append(VCARD_ITEM_SEPARATOR);
-                    builder.append(escapeCharacters(phoneticGivenName));
-                    builder.append(VCARD_ITEM_SEPARATOR);
-                    builder.append(VCARD_ITEM_SEPARATOR);
-                    builder.append(VCARD_COL_SEPARATOR);
-
-                    if (mUsesAndroidProperty) {
-                        final String phoneticName = VCardUtils
-                                .constructNameFromElements(mVCardType,
-                                        phoneticFamilyName, phoneticMiddleName,
-                                        phoneticGivenName);
-                        builder.append(VCARD_PROPERTY_X_PHONETIC_NAME);
-
-                        if (!VCardUtils.containsOnlyAscii(phoneticName)) {
-                            builder.append(VCARD_ATTR_SEPARATOR);
-                            builder.append(mVCardAttributeCharset);
-                        }
-
-                        builder.append(VCARD_DATA_SEPARATOR);
-                        // TODO: may need to make the text quoted-printable.
-                        builder.append(phoneticName);
-                        builder.append(VCARD_COL_SEPARATOR);
-                    }
+                    builder.append(mVCardAttributeCharset);
                 }
-            } else if (mIsDoCoMo) {
+
+                builder.append(VCARD_DATA_SEPARATOR);
+                builder.append(sortString);
+                builder.append(VCARD_COL_SEPARATOR);
+            } else {
+                // Note: There is no appropriate property for expressing
+                // phonetic name in
+                // VCard 2.1, while there is in VCard 3.0 (SORT-STRING).
+                // We chose to use DoCoMo's way since it is supported by a
+                // lot of Japanese mobile phones.
+                //
+                // TODO: should use Quoted-Pritable?
                 builder.append(VCARD_PROPERTY_SOUND);
                 builder.append(VCARD_ATTR_SEPARATOR);
                 builder.append(Constants.ATTR_TYPE_X_IRMC_N);
-                builder.append(VCARD_DATA_SEPARATOR);
+                builder.append(VCARD_ATTR_SEPARATOR);
+
+                if (!(VCardUtils.containsOnlyPrintableAscii(phoneticFamilyName) &&
+                        VCardUtils.containsOnlyPrintableAscii(phoneticMiddleName) &&
+                        VCardUtils.containsOnlyPrintableAscii(phoneticGivenName))) {
+                    builder.append(mVCardAttributeCharset);
+                    builder.append(VCARD_DATA_SEPARATOR);
+                }
+
+                builder.append(escapeCharacters(phoneticFamilyName));
                 builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(escapeCharacters(phoneticMiddleName));
                 builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(escapeCharacters(phoneticGivenName));
                 builder.append(VCARD_ITEM_SEPARATOR);
                 builder.append(VCARD_ITEM_SEPARATOR);
                 builder.append(VCARD_COL_SEPARATOR);
             }
+        } else if (mIsDoCoMo) {
+            builder.append(VCARD_PROPERTY_SOUND);
+            builder.append(VCARD_ATTR_SEPARATOR);
+            builder.append(Constants.ATTR_TYPE_X_IRMC_N);
+            builder.append(VCARD_DATA_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_ITEM_SEPARATOR);
+            builder.append(VCARD_COL_SEPARATOR);
+        }
 
-            if (mUsesDefactProperty) {
-                if (!TextUtils.isEmpty(phoneticGivenName)) {
-                    builder.append(VCARD_PROPERTY_X_PHONETIC_FIRST_NAME);
-                    builder.append(VCARD_DATA_SEPARATOR);
-                    builder.append(phoneticGivenName);
-                    builder.append(VCARD_COL_SEPARATOR);
-                }
-                if (!TextUtils.isEmpty(phoneticMiddleName)) {
-                    builder.append(VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME);
-                    builder.append(VCARD_DATA_SEPARATOR);
-                    builder.append(phoneticMiddleName);
-                    builder.append(VCARD_COL_SEPARATOR);
-                }
-                if (!TextUtils.isEmpty(phoneticFamilyName)) {
-                    builder.append(VCARD_PROPERTY_X_PHONETIC_LAST_NAME);
-                    builder.append(VCARD_DATA_SEPARATOR);
-                    builder.append(phoneticFamilyName);
-                    builder.append(VCARD_COL_SEPARATOR);
-                }
+        if (mUsesDefactProperty) {
+            if (!TextUtils.isEmpty(phoneticGivenName)) {
+                builder.append(VCARD_PROPERTY_X_PHONETIC_FIRST_NAME);
+                builder.append(VCARD_DATA_SEPARATOR);
+                builder.append(phoneticGivenName);
+                builder.append(VCARD_COL_SEPARATOR);
+            }
+            if (!TextUtils.isEmpty(phoneticMiddleName)) {
+                builder.append(VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME);
+                builder.append(VCARD_DATA_SEPARATOR);
+                builder.append(phoneticMiddleName);
+                builder.append(VCARD_COL_SEPARATOR);
+            }
+            if (!TextUtils.isEmpty(phoneticFamilyName)) {
+                builder.append(VCARD_PROPERTY_X_PHONETIC_LAST_NAME);
+                builder.append(VCARD_DATA_SEPARATOR);
+                builder.append(phoneticFamilyName);
+                builder.append(VCARD_COL_SEPARATOR);
             }
         }
     }
@@ -974,7 +982,7 @@
                 }
                 builder.append(propertyNickname);
 
-                if (!VCardUtils.containsOnlyAscii(propertyNickname)) {
+                if (!VCardUtils.containsOnlyPrintableAscii(propertyNickname)) {
                     //  Strictly, this is not valid in vCard 3.0. See above.
                     builder.append(VCARD_ATTR_SEPARATOR);
                     builder.append(mVCardAttributeCharset);
@@ -991,16 +999,31 @@
             final Map<String, List<ContentValues>> contentValuesListMap) {
         final List<ContentValues> contentValuesList = contentValuesListMap
                 .get(Phone.CONTENT_ITEM_TYPE);
+        boolean phoneLineExists = false;
         if (contentValuesList != null) {
+            Set<String> phoneSet = new HashSet<String>();
             for (ContentValues contentValues : contentValuesList) {
-                Integer phoneType = contentValues.getAsInteger(Phone.TYPE);
-                int phoneTypeAsPrimitive =
-                    (phoneType == null ? Phone.TYPE_HOME : phoneType);
-                appendVCardTelephoneLine(builder, phoneTypeAsPrimitive,
-                        contentValues.getAsString(Phone.LABEL),
-                        contentValues.getAsString(Phone.NUMBER));
+                final Integer typeAsObject = contentValues.getAsInteger(Phone.TYPE);
+                final String label = contentValues.getAsString(Phone.LABEL);
+                String phoneNumber = contentValues.getAsString(Phone.NUMBER);
+                if (phoneNumber != null) {
+                    phoneNumber = phoneNumber.trim();
+                }
+                if (TextUtils.isEmpty(phoneNumber)) {
+                    continue;
+                }
+                phoneLineExists = true;
+                int type = (typeAsObject != null ? typeAsObject : Phone.TYPE_HOME);
+                // TODO: Premature, since this allows two phone numbers which are
+                //        same from the view of phone number format (e.g. "100" v.s. "1-0-0")
+                if (!phoneSet.contains(phoneNumber)) {
+                    phoneSet.add(phoneNumber);
+                    appendVCardTelephoneLine(builder, type, label, phoneNumber);
+                }
             }
-        } else if (mIsDoCoMo) {
+        }
+
+        if (!phoneLineExists && mIsDoCoMo) {
             appendVCardTelephoneLine(builder, Phone.TYPE_HOME, "", "");
         }
     }
@@ -1009,14 +1032,31 @@
             final Map<String, List<ContentValues>> contentValuesListMap) {
         final List<ContentValues> contentValuesList = contentValuesListMap
                 .get(Email.CONTENT_ITEM_TYPE);
+        boolean emailAddressExists = false;
         if (contentValuesList != null) {
+            Set<String> addressSet = new HashSet<String>();
             for (ContentValues contentValues : contentValuesList) {
-                appendVCardEmailLine(builder, contentValues
-                        .getAsInteger(Email.TYPE), contentValues
-                        .getAsString(Email.LABEL), contentValues
-                        .getAsString(Email.DATA));
+                Integer typeAsObject = contentValues.getAsInteger(Email.TYPE);
+                final int type = (typeAsObject != null ?
+                        typeAsObject : Email.TYPE_OTHER);
+                final String label = contentValues.getAsString(Email.LABEL);
+                String emailAddress = contentValues.getAsString(Email.DATA);
+                if (emailAddress != null) {
+                    emailAddress = emailAddress.trim();
+                }
+                if (TextUtils.isEmpty(emailAddress)) {
+                    continue;
+                }
+                emailAddressExists = true;
+                // Do not allow completely same email address line emitted into each file.
+                if (!addressSet.contains(emailAddress)) {
+                    addressSet.add(emailAddress);
+                    appendVCardEmailLine(builder, type, label, emailAddress);
+                }
             }
-        } else if (mIsDoCoMo) {
+        }
+
+        if (!emailAddressExists && mIsDoCoMo) {
             appendVCardEmailLine(builder, Email.TYPE_HOME, "", "");
         }
     }
@@ -1087,7 +1127,9 @@
         for (ContentValues contentValues : contentValuesList) {
             final Integer type = contentValues.getAsInteger(StructuredPostal.TYPE);
             final String label = contentValues.getAsString(StructuredPostal.LABEL);
-            appendVCardPostalLine(builder, type, label, contentValues);
+            if (type != null) {
+                appendVCardPostalLine(builder, type, label, contentValues);
+            }
         }
     }
 
@@ -1099,6 +1141,12 @@
             for (ContentValues contentValues : contentValuesList) {
                 Integer protocol = contentValues.getAsInteger(Im.PROTOCOL);
                 String data = contentValues.getAsString(Im.DATA);
+                if (data != null) {
+                    data = data.trim();
+                }
+                if (TextUtils.isEmpty(data)) {
+                    continue;
+                }
 
                 if (protocol != null && protocol == Im.PROTOCOL_GOOGLE_TALK) {
                     if (VCardConfig.usesAndroidSpecificProperty(mVCardType)) {
@@ -1116,8 +1164,13 @@
                 .get(Website.CONTENT_ITEM_TYPE);
         if (contentValuesList != null) {
             for (ContentValues contentValues : contentValuesList) {
-                final String website = contentValues.getAsString(Website.URL);
-                appendVCardLine(builder, VCARD_PROPERTY_URL, website);
+                String website = contentValues.getAsString(Website.URL);
+                if (website != null) {
+                    website = website.trim();
+                }
+                if (!TextUtils.isEmpty(website)) {
+                    appendVCardLine(builder, VCARD_PROPERTY_URL, website);
+                }
             }
         }
     }
@@ -1130,8 +1183,13 @@
             // Theoretically, there must be only one birthday for each vCard data and
             // we are afraid of some parse error occuring in some devices, so
             // we emit only one birthday entry for now.
-            final String birthday = contentValuesList.get(0).getAsString(Birthday.BIRTHDAY);
-            appendVCardLine(builder, VCARD_PROPERTY_BIRTHDAY, birthday);
+            String birthday = contentValuesList.get(0).getAsString(Birthday.BIRTHDAY);
+            if (birthday != null) {
+                birthday = birthday.trim();
+            }
+            if (!TextUtils.isEmpty(birthday)) {
+                appendVCardLine(builder, VCARD_PROPERTY_BIRTHDAY, birthday);
+            }
         }
     }
 
@@ -1141,14 +1199,29 @@
                 .get(Organization.CONTENT_ITEM_TYPE);
         if (contentValuesList != null) {
             for (ContentValues contentValues : contentValuesList) {
-                final String company = contentValues
+                String company = contentValues
                         .getAsString(Organization.COMPANY);
-                final String title = contentValues
+                if (company != null) {
+                    company = company.trim();
+                }
+                String title = contentValues
                         .getAsString(Organization.TITLE);
-                appendVCardLine(builder, VCARD_PROPERTY_ORG, company, true,
-                        mUsesQuotedPrintable);
-                appendVCardLine(builder, VCARD_PROPERTY_TITLE, title, true,
-                        mUsesQuotedPrintable);
+                if (title != null) {
+                    title = title.trim();
+                }
+
+                if (!TextUtils.isEmpty(company)) {
+                    appendVCardLine(builder, VCARD_PROPERTY_ORG, company,
+                            !VCardUtils.containsOnlyPrintableAscii(company),
+                            (mUsesQuotedPrintable &&
+                                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(company)));
+                }
+                if (!TextUtils.isEmpty(title)) {
+                    appendVCardLine(builder, VCARD_PROPERTY_TITLE, title,
+                            !VCardUtils.containsOnlyPrintableAscii(title),
+                            (mUsesQuotedPrintable &&
+                                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(title)));
+                }
             }
         }
     }
@@ -1201,7 +1274,10 @@
                 StringBuilder noteBuilder = new StringBuilder();
                 boolean first = true;
                 for (ContentValues contentValues : contentValuesList) {
-                    final String note = contentValues.getAsString(Note.NOTE);
+                    String note = contentValues.getAsString(Note.NOTE);
+                    if (note == null) {
+                        note = "";
+                    }
                     if (note.length() > 0) {
                         if (first) {
                             first = false;
@@ -1211,14 +1287,27 @@
                         noteBuilder.append(note);
                     }
                 }
-                appendVCardLine(builder, VCARD_PROPERTY_NOTE, noteBuilder.toString(),
-                        true, mUsesQuotedPrintable);
+                final String noteStr = noteBuilder.toString();
+                // This means we scan noteStr completely twice, which is redundant.
+                // But for now, we assume this is not so time-consuming..
+                final boolean shouldAppendCharsetInfo =
+                    !VCardUtils.containsOnlyPrintableAscii(noteStr);
+                final boolean reallyUseQuotedPrintable =
+                        (mUsesQuotedPrintable &&
+                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
+                appendVCardLine(builder, VCARD_PROPERTY_NOTE, noteStr,
+                        shouldAppendCharsetInfo, reallyUseQuotedPrintable);
             } else {
                 for (ContentValues contentValues : contentValuesList) {
-                    final String note = contentValues.getAsString(Note.NOTE);
-                    if (!TextUtils.isEmpty(note)) {
-                        appendVCardLine(builder, VCARD_PROPERTY_NOTE, note, true,
-                                mUsesQuotedPrintable);
+                    final String noteStr = contentValues.getAsString(Note.NOTE);
+                    if (!TextUtils.isEmpty(noteStr)) {
+                        final boolean shouldAppendCharsetInfo =
+                                !VCardUtils.containsOnlyPrintableAscii(noteStr);
+                        final boolean reallyUseQuotedPrintable =
+                                (mUsesQuotedPrintable &&
+                                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
+                        appendVCardLine(builder, VCARD_PROPERTY_NOTE, noteStr,
+                                shouldAppendCharsetInfo, reallyUseQuotedPrintable);
                     }
                 }
             }
@@ -1339,15 +1428,31 @@
         builder.append(VCARD_PROPERTY_ADR);
         builder.append(VCARD_ATTR_SEPARATOR);
 
+        // Note: Not sure why we need to emit "empty" line even when actual data does not exist.
+        // There may be some reason or may not be any. We keep safer side.
+        // TODO: investigate this.
         boolean dataExists = false;
         String[] dataArray = VCardUtils.getVCardPostalElements(contentValues);
+        boolean actuallyUseQuotedPrintable = false;
+        boolean shouldAppendCharset = false;
+        for (String data : dataArray) {
+            if (!TextUtils.isEmpty(data)) {
+                dataExists = true;
+                if (!shouldAppendCharset && !VCardUtils.containsOnlyPrintableAscii(data)) {
+                    shouldAppendCharset = true;
+                }
+                if (mUsesQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(data)) {
+                    actuallyUseQuotedPrintable = true;
+                    break;
+                }
+            }
+        }
+
         int length = dataArray.length;
-        final boolean useQuotedPrintable = mUsesQuotedPrintable;
         for (int i = 0; i < length; i++) {
             String data = dataArray[i];
             if (!TextUtils.isEmpty(data)) {
-                dataExists = true;
-                if (useQuotedPrintable) {
+                if (actuallyUseQuotedPrintable) {
                     dataArray[i] = encodeQuotedPrintable(data);
                 } else {
                     dataArray[i] = escapeCharacters(data);
@@ -1394,25 +1499,40 @@
             }
         }
 
-        if (typeAsString != null) {
-            appendTypeAttribute(builder, typeAsString);
-        }
+        // Attribute(s).
 
-        if (dataExists) {
-            // Strictly, vCard 3.0 does not allow exporters to emit charset information,
-            // but we will add it since the information should be useful for importers,
-            //
-            // Assume no parser does not emit error with this attribute in vCard 3.0.
+        {
+            boolean shouldAppendAttrSeparator = false;
             if (typeAsString != null) {
-                builder.append(VCARD_ATTR_SEPARATOR);
+                appendTypeAttribute(builder, typeAsString);
+                shouldAppendAttrSeparator = true;
             }
-            builder.append(mVCardAttributeCharset);
 
-            if (useQuotedPrintable) {
-                builder.append(VCARD_ATTR_SEPARATOR);
-                builder.append(VCARD_ATTR_ENCODING_QP);
+            if (dataExists) {
+                if (shouldAppendCharset) {
+                    // Strictly, vCard 3.0 does not allow exporters to emit charset information,
+                    // but we will add it since the information should be useful for importers,
+                    //
+                    // Assume no parser does not emit error with this attribute in vCard 3.0.
+                    if (shouldAppendAttrSeparator) {
+                        builder.append(VCARD_ATTR_SEPARATOR);
+                    }
+                    builder.append(mVCardAttributeCharset);
+                    shouldAppendAttrSeparator = true;
+                }
+
+                if (actuallyUseQuotedPrintable) {
+                    if (shouldAppendAttrSeparator) {
+                        builder.append(VCARD_ATTR_SEPARATOR);
+                    }
+                    builder.append(VCARD_ATTR_ENCODING_QP);
+                    shouldAppendAttrSeparator = true;
+                }
             }
         }
+
+        // Property values.
+
         builder.append(VCARD_DATA_SEPARATOR);
         if (dataExists) {
             // The elements in dataArray are already encoded to quoted printable
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
index ffceade..4f50103 100644
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -283,7 +283,7 @@
         return builder.toString();
     }
     
-    public static boolean containsOnlyAscii(String str) {
+    public static boolean containsOnlyPrintableAscii(String str) {
         if (TextUtils.isEmpty(str)) {
             return true;
         }
@@ -299,13 +299,35 @@
         }
         return true;
     }
-    
+
+    /**
+     * This is useful when checking the string should be encoded into quoted-printable
+     * or not, which is required by vCard 2.1.
+     * See the definition of "7bit" in vCard 2.1 spec for more information.
+     */
+    public static boolean containsOnlyNonCrLfPrintableAscii(String str) {
+        if (TextUtils.isEmpty(str)) {
+            return true;
+        }
+
+        final int length = str.length();
+        final int asciiFirst = 0x20;
+        final int asciiLast = 0x126;
+        for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
+            int c = str.codePointAt(i);
+            if (c < asciiFirst || asciiLast < c || c == '\n' || c == '\r') {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * This is useful since vCard 3.0 often requires the ("X-") properties and groups
      * should contain only alphabets, digits, and hyphen.
      * 
      * Note: It is already known some devices (wrongly) outputs properties with characters
-     *       which should not be in the field. One example is "X-GOOGLE TALK". We appreciate
+     *       which should not be in the field. One example is "X-GOOGLE TALK". We accept
      *       such kind of input but must never output it unless the target is very specific
      *       to the device which is able to parse the malformed input. 
      */
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1b13f52..70a20d6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -57,6 +57,14 @@
     public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
 
     /**
+     * A query parameter key used to specify the package that is requesting a query.
+     * This is used for restricting data based on package name.
+     *
+     * @hide
+     */
+    public static final String REQUESTING_PACKAGE_PARAM_KEY = "requesting_package";
+
+    /**
      * @hide should be removed when users are updated to refer to SyncState
      * @deprecated use SyncState instead
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1cd4506..f27902d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3191,6 +3191,13 @@
                 "vending_pd_resend_frequency_ms";
 
         /**
+         * Time before an asset in the 'DOWNLOADING' state is considered ready
+         * for an install kick on the client.
+         */
+        public static final String VENDING_DOWNLOADING_KICK_TIMEOUT_MS =
+                "vending_downloading_kick_ms";
+
+        /**
          * Size of buffer in bytes for Vending to use when reading cache files.
          */
         public static final String VENDING_DISK_INPUT_BUFFER_BYTES =
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index dfc16f5..6995107 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -72,6 +72,24 @@
     }
 
     /**
+     * @hide
+     * Returns the maximum scroll value in x.
+     */
+    public static int getMaxScrollX(TextView widget, Layout layout, int y) {
+        int top = layout.getLineForVertical(y);
+        int bottom = layout.getLineForVertical(y + widget.getHeight()
+                - widget.getTotalPaddingTop() -widget.getTotalPaddingBottom());
+        int left = Integer.MAX_VALUE;
+        int right = 0;
+        for (int i = top; i <= bottom; i++) {
+            left = (int) Math.min(left, layout.getLineLeft(i));
+            right = (int) Math.max(right, layout.getLineRight(i));
+        }
+        return right - left - widget.getWidth() - widget.getTotalPaddingLeft()
+                - widget.getTotalPaddingRight();
+    }
+
+    /**
      * Handles touch events for dragging.  You may want to do other actions
      * like moving the cursor on touch as well.
      */
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 65ce158..f479124 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -276,25 +276,6 @@
     }
 
     /**
-     *  Create a fake touch up event at (x,y) with respect to this WebTextView.
-     *  This is used by WebView to act as though a touch event which happened
-     *  before we placed the WebTextView actually hit it, so that it can place
-     *  the cursor accordingly.
-     */
-    /* package */ void fakeTouchEvent(float x, float y) {
-        // We need to ensure that there is a Layout, since the Layout is used
-        // in determining where to place the cursor.
-        if (getLayout() == null) {
-            measure(mWidthSpec, mHeightSpec);
-        }
-        // Create a fake touch up, which is used to place the cursor.
-        MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
-                x, y, 0);
-        onTouchEvent(ev);
-        ev.recycle();
-    }
-
-    /**
      *  Determine whether this WebTextView currently represents the node
      *  represented by ptr.
      *  @param  ptr Pointer to a node to compare to.
@@ -457,7 +438,14 @@
             int smallerSlop = slop/2;
             if (dx > smallerSlop || dy > smallerSlop) {
                 if (mWebView != null) {
-                    mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
+                    float maxScrollX = (float) Touch.getMaxScrollX(this,
+                                getLayout(), mScrollY);
+                    if (DebugFlags.WEB_TEXT_VIEW) {
+                        Log.v(LOGTAG, "onTouchEvent x=" + mScrollX + " y="
+                                + mScrollY + " maxX=" + maxScrollX);
+                    }
+                    mWebView.scrollFocusedTextInput(maxScrollX > 0 ?
+                            mScrollX / maxScrollX : 0, mScrollY);
                 }
                 mScrolled = true;
                 return true;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8858b81..68a9a92 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1111,6 +1111,12 @@
         ArrayList<byte[]> history = new ArrayList<byte[]>(size);
         for (int i = 0; i < size; i++) {
             WebHistoryItem item = list.getItemAtIndex(i);
+            if (null == item) {
+                // FIXME: this shouldn't happen
+                // need to determine how item got set to null
+                Log.w(LOGTAG, "saveState: Unexpected null history item.");
+                return null;
+            }
             byte[] data = item.getFlattenedData();
             if (data == null) {
                 // It would be very odd to not have any data for a given history
@@ -1917,12 +1923,15 @@
                 int oldY = mScrollY;
                 mScrollX = pinLocX(mScrollX);
                 mScrollY = pinLocY(mScrollY);
-                // android.util.Log.d("skia", "recordNewContentSize -
-                // abortAnimation");
-                abortAnimation(); // just in case
                 if (oldX != mScrollX || oldY != mScrollY) {
                     sendOurVisibleRect();
                 }
+                if (!mScroller.isFinished()) {
+                    // We are in the middle of a scroll.  Repin the final scroll
+                    // position.
+                    mScroller.setFinalX(pinLocX(mScroller.getFinalX()));
+                    mScroller.setFinalY(pinLocY(mScroller.getFinalY()));
+                }
             }
         }
         contentSizeChanged(updateLayout);
@@ -3004,17 +3013,6 @@
             if (mWebTextView == null) return;
 
             imm.showSoftInput(mWebTextView, 0);
-            // Now we need to fake a touch event to place the cursor where the
-            // user touched.
-            AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
-                    mWebTextView.getLayoutParams();
-            if (lp != null) {
-                // Take the last touch and adjust for the location of the
-                // WebTextView.
-                float x = mLastTouchX + (float) (mScrollX - lp.x);
-                float y = mLastTouchY + (float) (mScrollY - lp.y);
-                mWebTextView.fakeTouchEvent(x, y);
-            }
             if (mInZoomOverview) {
                 // if in zoom overview mode, call doDoubleTap() to bring it back
                 // to normal mode so that user can enter text.
@@ -4502,18 +4500,19 @@
 
     /**
      * Scroll the focused text field/area to match the WebTextView
-     * @param x New x position of the WebTextView in view coordinates
+     * @param xPercent New x position of the WebTextView from 0 to 1.
      * @param y New y position of the WebTextView in view coordinates
      */
-    /*package*/ void scrollFocusedTextInput(int x, int y) {
+    /*package*/ void scrollFocusedTextInput(float xPercent, int y) {
         if (!inEditingMode() || mWebViewCore == null) {
             return;
         }
-        mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContentX(x),
+        mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT,
                 // Since this position is relative to the top of the text input
                 // field, we do not need to take the title bar's height into
                 // consideration.
-                viewToContentDimension(y));
+                viewToContentDimension(y),
+                new Float(xPercent));
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8b6746e..e2aa1d0 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -872,7 +872,8 @@
                             break;
 
                         case SCROLL_TEXT_INPUT:
-                            nativeScrollFocusedTextInput(msg.arg1, msg.arg2);
+                            nativeScrollFocusedTextInput(
+                                    ((Float) msg.obj).floatValue(), msg.arg1);
                             break;
 
                         case LOAD_URL:
@@ -2076,9 +2077,9 @@
     private native void nativeUpdateFrameCacheIfLoading();
 
     /**
-     * Scroll the focused textfield to (x, y) in document space
+     * Scroll the focused textfield to (xPercent, y) in document space
      */
-    private native void nativeScrollFocusedTextInput(int x, int y);
+    private native void nativeScrollFocusedTextInput(float xPercent, int y);
 
     // these must be in document space (i.e. not scaled/zoomed).
     private native void nativeSetScrollOffset(int gen, int dx, int dy);
diff --git a/core/java/android/widget/FasttrackBadgeWidget.java b/core/java/android/widget/FasttrackBadgeWidget.java
index 8c8e054..ba8539f 100644
--- a/core/java/android/widget/FasttrackBadgeWidget.java
+++ b/core/java/android/widget/FasttrackBadgeWidget.java
@@ -33,6 +33,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
+import com.android.internal.R;
 
 /**
  * Widget used to show an image with the standard fasttrack badge
@@ -48,6 +49,7 @@
     private int mMode;
     private QueryHandler mQueryHandler;
     private Drawable mBadgeBackground;
+    private Drawable mNoBadgeBackground;
 
     protected String[] mExcludeMimes = null;
 
@@ -119,7 +121,10 @@
 
     private void onContactUriChanged() {
         if (mContactUri == null && mContactEmail == null && mContactPhone == null) {
-            setBackgroundDrawable(null);
+            if (mNoBadgeBackground == null) {
+                mNoBadgeBackground = getResources().getDrawable(R.drawable.fasttrack_nobadge);
+            }
+            setBackgroundDrawable(mNoBadgeBackground);
         } else {
             setBackgroundDrawable(mBadgeBackground);
         }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 70555dc..ffe9908 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -220,6 +220,8 @@
                 selectedView = temp;
             }
 
+            // mReferenceView will change with each call to makeRow()
+            // do not cache in a local variable outside of this loop
             nextTop = mReferenceView.getBottom() + mVerticalSpacing;
 
             pos += mNumColumns;
@@ -233,7 +235,8 @@
         final int horizontalSpacing = mHorizontalSpacing;
 
         int last;
-        int nextLeft = mListPadding.left + ((mStretchMode == STRETCH_SPACING_UNIFORM) ? horizontalSpacing : 0);
+        int nextLeft = mListPadding.left +
+                ((mStretchMode == STRETCH_SPACING_UNIFORM) ? horizontalSpacing : 0);
 
         if (!mStackFromBottom) {
             last = Math.min(startPos + mNumColumns, mItemCount);
@@ -252,16 +255,14 @@
         final boolean inClick = touchModeDrawsInPressedState();
         final int selectedPosition = mSelectedPosition;
 
-        mReferenceView = null;
-
+        View child = null;
         for (int pos = startPos; pos < last; pos++) {
             // is this the selected item?
             boolean selected = pos == selectedPosition;
             // does the list view have focus or contain focus
 
             final int where = flow ? -1 : pos - startPos;
-            final View child = makeAndAddView(pos, y, flow, nextLeft, selected, where);
-            mReferenceView = child;
+            child = makeAndAddView(pos, y, flow, nextLeft, selected, where);
 
             nextLeft += columnWidth;
             if (pos < last - 1) {
@@ -273,6 +274,8 @@
             }
         }
 
+        mReferenceView = child;
+        
         if (selectedView != null) {
             mReferenceViewInSelectedRow = mReferenceView;
         }
@@ -465,6 +468,11 @@
         mFirstPosition = motionRowStart;
 
         final View referenceView = mReferenceView;
+        // We didn't have anything to layout, bail out
+        if (referenceView == null) {
+            return null;
+        }
+
         final int verticalSpacing = mVerticalSpacing;
 
         View above;
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index cfcf111..0d0a3c2 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -213,6 +213,12 @@
         void onPatternCleared();
 
         /**
+         * The user extended the pattern currently being drawn by one cell.
+         * @param pattern The pattern with newly added cell.
+         */
+        void onPatternCellAdded(List<Cell> pattern);
+
+        /**
          * A pattern was detected from the user.
          * @param pattern The pattern.
          */
@@ -447,6 +453,9 @@
     private void addCellToPattern(Cell newCell) {
         mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
         mPattern.add(newCell);
+        if (mOnPatternListener != null) {
+            mOnPatternListener.onPatternCellAdded(mPattern);
+        }
     }
 
     // helper method to find which cell a point maps to
diff --git a/core/res/res/drawable-hdpi/contact_header_bg.9.png b/core/res/res/drawable-hdpi/contact_header_bg.9.png
new file mode 100755
index 0000000..981b2e9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/contact_header_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_contact_picture_2.png b/core/res/res/drawable-hdpi/ic_contact_picture_2.png
new file mode 100755
index 0000000..5e65276
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_contact_picture_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_contact_picture_3.png b/core/res/res/drawable-hdpi/ic_contact_picture_3.png
new file mode 100755
index 0000000..a8ec1e1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_contact_picture_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png
new file mode 100755
index 0000000..24e07ab
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_h.png b/core/res/res/drawable-hdpi/stat_sys_data_in_h.png
new file mode 100755
index 0000000..f2f6daa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png
new file mode 100755
index 0000000..5d6ef05
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_h.png b/core/res/res/drawable-hdpi/stat_sys_data_out_h.png
new file mode 100755
index 0000000..5e3122d6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/statusbar_background.9.png b/core/res/res/drawable-hdpi/statusbar_background.9.png
new file mode 100644
index 0000000..dcca695
--- /dev/null
+++ b/core/res/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/statusbar_background.png b/core/res/res/drawable-hdpi/statusbar_background.png
deleted file mode 100644
index c2b3a5e..0000000
--- a/core/res/res/drawable-hdpi/statusbar_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_def_app_icon.png b/core/res/res/drawable-hdpi/sym_def_app_icon.png
index 4b5384f..4870fbb 100644
--- a/core/res/res/drawable-hdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_medium.9.png b/core/res/res/drawable-hdpi/title_bar_medium.9.png
new file mode 100644
index 0000000..311a54a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_medium.png b/core/res/res/drawable-hdpi/title_bar_medium.png
deleted file mode 100644
index c13dd26..0000000
--- a/core/res/res/drawable-hdpi/title_bar_medium.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_portrait.9.png b/core/res/res/drawable-hdpi/title_bar_portrait.9.png
index 161432f..70f7cc2 100644
--- a/core/res/res/drawable-hdpi/title_bar_portrait.9.png
+++ b/core/res/res/drawable-hdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_shadow.9.png b/core/res/res/drawable-hdpi/title_bar_shadow.9.png
index e67f457..e6dab63 100644
--- a/core/res/res/drawable-hdpi/title_bar_shadow.9.png
+++ b/core/res/res/drawable-hdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_tall.9.png b/core/res/res/drawable-hdpi/title_bar_tall.9.png
new file mode 100644
index 0000000..5c1a69f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_tall.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_tall.png b/core/res/res/drawable-hdpi/title_bar_tall.png
deleted file mode 100644
index f177440..0000000
--- a/core/res/res/drawable-hdpi/title_bar_tall.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/bottombar_565.png b/core/res/res/drawable-land-hdpi/bottombar_565.png
new file mode 100755
index 0000000..9df56ca
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/bottombar_565.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/statusbar_background.png b/core/res/res/drawable-land-hdpi/statusbar_background.png
deleted file mode 100644
index 4a955c5..0000000
--- a/core/res/res/drawable-land-hdpi/statusbar_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/title_bar_tall.png b/core/res/res/drawable-land-hdpi/title_bar_tall.png
deleted file mode 100644
index 96b5ffe..0000000
--- a/core/res/res/drawable-land-hdpi/title_bar_tall.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-land/bottombar_565.png b/core/res/res/drawable-land-mdpi/bottombar_565.png
similarity index 100%
rename from core/res/res/drawable-land/bottombar_565.png
rename to core/res/res/drawable-land-mdpi/bottombar_565.png
Binary files differ
diff --git a/core/res/res/drawable-land-mdpi/statusbar_background.png b/core/res/res/drawable-land-mdpi/statusbar_background.png
deleted file mode 100644
index ef61e52..0000000
--- a/core/res/res/drawable-land-mdpi/statusbar_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-land-mdpi/title_bar_tall.png b/core/res/res/drawable-land-mdpi/title_bar_tall.png
deleted file mode 100644
index 16290fb..0000000
--- a/core/res/res/drawable-land-mdpi/title_bar_tall.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/contact_header_bg.9.png b/core/res/res/drawable-mdpi/contact_header_bg.9.png
similarity index 100%
rename from core/res/res/drawable/contact_header_bg.9.png
rename to core/res/res/drawable-mdpi/contact_header_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture_2.png b/core/res/res/drawable-mdpi/ic_contact_picture_2.png
similarity index 100%
rename from core/res/res/drawable/ic_contact_picture_2.png
rename to core/res/res/drawable-mdpi/ic_contact_picture_2.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture_3.png b/core/res/res/drawable-mdpi/ic_contact_picture_3.png
similarity index 100%
rename from core/res/res/drawable/ic_contact_picture_3.png
rename to core/res/res/drawable-mdpi/ic_contact_picture_3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_h.png b/core/res/res/drawable-mdpi/stat_sys_data_connected_h.png
similarity index 100%
rename from core/res/res/drawable/stat_sys_data_connected_h.png
rename to core/res/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_h.png b/core/res/res/drawable-mdpi/stat_sys_data_in_h.png
similarity index 100%
rename from core/res/res/drawable/stat_sys_data_in_h.png
rename to core/res/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_h.png b/core/res/res/drawable-mdpi/stat_sys_data_inandout_h.png
similarity index 100%
rename from core/res/res/drawable/stat_sys_data_inandout_h.png
rename to core/res/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_h.png b/core/res/res/drawable-mdpi/stat_sys_data_out_h.png
similarity index 100%
rename from core/res/res/drawable/stat_sys_data_out_h.png
rename to core/res/res/drawable-mdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/statusbar_background.9.png b/core/res/res/drawable-mdpi/statusbar_background.9.png
new file mode 100644
index 0000000..eb7c1a4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/statusbar_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/statusbar_background.png b/core/res/res/drawable-mdpi/statusbar_background.png
deleted file mode 100644
index 204d76a..0000000
--- a/core/res/res/drawable-mdpi/statusbar_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_medium.9.png b/core/res/res/drawable-mdpi/title_bar_medium.9.png
new file mode 100644
index 0000000..2d41d02
--- /dev/null
+++ b/core/res/res/drawable-mdpi/title_bar_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_medium.png b/core/res/res/drawable-mdpi/title_bar_medium.png
deleted file mode 100644
index 9d01f79..0000000
--- a/core/res/res/drawable-mdpi/title_bar_medium.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_portrait.9.png b/core/res/res/drawable-mdpi/title_bar_portrait.9.png
index 482d82e..13b18d8 100644
--- a/core/res/res/drawable-mdpi/title_bar_portrait.9.png
+++ b/core/res/res/drawable-mdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_shadow.9.png b/core/res/res/drawable-mdpi/title_bar_shadow.9.png
index 08723665..dbcefee 100644
--- a/core/res/res/drawable-mdpi/title_bar_shadow.9.png
+++ b/core/res/res/drawable-mdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_tall.9.png b/core/res/res/drawable-mdpi/title_bar_tall.9.png
new file mode 100644
index 0000000..5a050c4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/title_bar_tall.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_tall.png b/core/res/res/drawable-mdpi/title_bar_tall.png
deleted file mode 100644
index cd565dc..0000000
--- a/core/res/res/drawable-mdpi/title_bar_tall.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_nobadge.xml b/core/res/res/drawable/fasttrack_nobadge.xml
new file mode 100644
index 0000000..538e165
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_nobadge.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* bubble_with_chats.xml
+**
+** Copyright 2009, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/fasttrack_nobadge_pressed" />
+    <item android:state_selected="true" android:drawable="@drawable/fasttrack_nobadge_highlight" />
+    <item android:state_focused="true" android:drawable="@drawable/fasttrack_nobadge_highlight" />
+    <item android:state_enabled="false" android:drawable="@drawable/fasttrack_nobadge_normal" />
+    <item android:drawable="@drawable/fasttrack_nobadge_normal" />
+</selector>
diff --git a/core/res/res/drawable/fasttrack_nobadge_highlight.9.png b/core/res/res/drawable/fasttrack_nobadge_highlight.9.png
new file mode 100644
index 0000000..f0f50b3
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_nobadge_highlight.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_nobadge_normal.9.png b/core/res/res/drawable/fasttrack_nobadge_normal.9.png
new file mode 100644
index 0000000..01cc9dc
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_nobadge_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_nobadge_pressed.9.png b/core/res/res/drawable/fasttrack_nobadge_pressed.9.png
new file mode 100644
index 0000000..6e22c87
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_nobadge_pressed.9.png
Binary files differ
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3d6d273..3e3f87b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1102,8 +1102,8 @@
         return res;
     }
 
-    public native int native_breakText(char[] text, int index, int count,
-                                       float maxWidth, float[] measuredWidth);
+    private native int native_breakText(char[] text, int index, int count,
+                                        float maxWidth, float[] measuredWidth);
 
     /**
      * Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1174,8 +1174,8 @@
         return res;
     }
 
-    public native int native_breakText(String text, boolean measureForwards,
-                                       float maxWidth, float[] measuredWidth);
+    private native int native_breakText(String text, boolean measureForwards,
+                                        float maxWidth, float[] measuredWidth);
 
     /**
      * Return the advance widths for the characters in the string.
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 2f195a5..8919465 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -996,7 +996,7 @@
         "float", "(float, float)" },
     { "abs", (void *)&abs,
         "int", "(int)" },
-    { "absf", (void *)&fabs,
+    { "absf", (void *)&fabsf,
         "float", "(float)" },
     { "sinf_fast", (void *)&SC_sinf_fast,
         "float", "(float)" },
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d6463a1..bb16215a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -725,7 +725,7 @@
      *         false if otherwise
      */
     public boolean isBluetoothA2dpOn() {
-        if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,"") 
+        if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,"")
             == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
             return false;
         } else {
@@ -750,7 +750,7 @@
      *         false if otherwise
      */
     public boolean isWiredHeadsetOn() {
-        if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,"") 
+        if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,"")
                 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
             return false;
         } else {
@@ -1063,7 +1063,9 @@
      *            {@link #FX_KEYPRESS_SPACEBAR},
      *            {@link #FX_KEYPRESS_DELETE},
      *            {@link #FX_KEYPRESS_RETURN},
-     * @param volume Sound effect volume
+     * @param volume Sound effect volume.
+     * The volume value is a raw scalar so UI controls should be scaled logarithmically.
+     * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used.
      * NOTE: This version is for applications that have their own
      * settings panel for enabling and controlling volume.
      */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 307cf22..f4c4586 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -619,11 +619,12 @@
     /** @see AudioManager#playSoundEffect(int) */
     public void playSoundEffect(int effectType) {
         sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
-                effectType, SOUND_EFFECT_VOLUME, null, 0);
+                effectType, -1, null, 0);
     }
 
     /** @see AudioManager#playSoundEffect(int, float) */
     public void playSoundEffectVolume(int effectType, float volume) {
+        loadSoundEffects();
         sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
                 effectType, (int) (volume * 1000), null, 0);
     }
@@ -634,6 +635,9 @@
      */
     public boolean loadSoundEffects() {
         synchronized (mSoundEffectsLock) {
+            if (mSoundPool != null) {
+                return true;
+            }
             mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
             if (mSoundPool == null) {
                 return false;
@@ -1197,10 +1201,20 @@
                 if (mSoundPool == null) {
                     return;
                 }
+                float volFloat;
+                // use STREAM_MUSIC volume attenuated by 3 dB if volume is not specified by caller
+                if (volume < 0) {
+                    // Same linear to log conversion as in native AudioSystem::linearToLog() (AudioSystem.cpp)
+                    float dBPerStep = (float)((0.5 * 100) / MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
+                    int musicVolIndex = (mStreamStates[AudioSystem.STREAM_MUSIC].mIndex + 5) / 10;
+                    float musicVoldB = dBPerStep * (musicVolIndex - MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
+                    volFloat = (float)Math.pow(10, (musicVoldB - 3)/20);
+                } else {
+                    volFloat = (float) volume / 1000.0f;
+                }
 
                 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
-                    float v = (float) volume / 1000.0f;
-                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], v, v, 0, 0, 1.0f);
+                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f);
                 } else {
                     MediaPlayer mediaPlayer = new MediaPlayer();
                     if (mediaPlayer != null) {
@@ -1209,6 +1223,7 @@
                             mediaPlayer.setDataSource(filePath);
                             mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
                             mediaPlayer.prepare();
+                            mediaPlayer.setVolume(volFloat, volFloat);
                             mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
                                 public void onCompletion(MediaPlayer mp) {
                                     cleanupPlayer(mp);
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index def0288..3cc115e 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -25,6 +25,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.util.Hashtable;
@@ -44,12 +45,6 @@
  *       only.
  */
 public class MiniThumbFile {
-    public static final int THUMBNAIL_TARGET_SIZE = 320;
-    public static final int MINI_THUMB_TARGET_SIZE = 96;
-    public static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384;
-    public static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128;
-    public static final int UNCONSTRAINED = -1;
-
     private static final String TAG = "MiniThumbFile";
     private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
     public static final int BYTES_PER_MINTHUMB = 10000;
@@ -57,6 +52,7 @@
     private Uri mUri;
     private RandomAccessFile mMiniThumbFile;
     private FileChannel mChannel;
+    private ByteBuffer mBuffer;
     private static Hashtable<String, MiniThumbFile> sThumbFiles =
         new Hashtable<String, MiniThumbFile>();
 
@@ -130,6 +126,7 @@
 
     public MiniThumbFile(Uri uri) {
         mUri = uri;
+        mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
     }
 
     public synchronized void deactivate() {
@@ -154,14 +151,16 @@
             long pos = id * BYTES_PER_MINTHUMB;
             FileLock lock = null;
             try {
-                lock = mChannel.lock();
+                mBuffer.clear();
+                mBuffer.limit(1 + 8);
+
+                lock = mChannel.lock(pos, 1 + 8, true);
                 // check that we can read the following 9 bytes
                 // (1 for the "status" and 8 for the long)
-                if (r.length() >= pos + 1 + 8) {
-                    r.seek(pos);
-                    if (r.readByte() == 1) {
-                        long fileMagic = r.readLong();
-                        return fileMagic;
+                if (mChannel.read(mBuffer, pos) == 9) {
+                    mBuffer.position(0);
+                    if (mBuffer.get() == 1) {
+                        return mBuffer.getLong();
                     }
                 }
             } catch (IOException ex) {
@@ -196,25 +195,20 @@
         long pos = id * BYTES_PER_MINTHUMB;
         FileLock lock = null;
         try {
-            lock = mChannel.lock();
             if (data != null) {
                 if (data.length > BYTES_PER_MINTHUMB - HEADER_SIZE) {
                     // not enough space to store it.
                     return;
                 }
-                r.seek(pos);
-                r.writeByte(0);     // we have no data in this slot
+                mBuffer.clear();
+                mBuffer.put((byte) 1);
+                mBuffer.putLong(magic);
+                mBuffer.putInt(data.length);
+                mBuffer.put(data);
+                mBuffer.flip();
 
-                // if magic is 0 then leave it alone
-                if (magic == 0) {
-                    r.skipBytes(8);
-                } else {
-                    r.writeLong(magic);
-                }
-                r.writeInt(data.length);
-                r.write(data);
-                r.seek(pos);
-                r.writeByte(1);  // we have data in this slot
+                lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
+                mChannel.write(mBuffer, pos);
             }
         } catch (IOException ex) {
             Log.e(TAG, "couldn't save mini thumbnail data for "
@@ -248,20 +242,22 @@
         long pos = id * BYTES_PER_MINTHUMB;
         FileLock lock = null;
         try {
-            lock = mChannel.lock();
-            r.seek(pos);
-            if (r.readByte() == 1) {
-                long magic = r.readLong();
-                int length = r.readInt();
-                int got = r.read(data, 0, length);
-                if (got != length) return null;
-                return data;
-            } else {
-                return null;
+            mBuffer.clear();
+            lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, true);
+            int size = mChannel.read(mBuffer, pos);
+            if (size > 1 + 8 + 4) { // flag, magic, length
+                mBuffer.position(0);
+                byte flag = mBuffer.get();
+                long magic = mBuffer.getLong();
+                int length = mBuffer.getInt();
+
+                if (size >= 1 + 8 + 4 + length && data.length >= length) {
+                    mBuffer.get(data, 0, length);
+                    return data;
+                }
             }
         } catch (IOException ex) {
-            Log.w(TAG, "got exception when reading thumbnail: " + ex);
-            return null;
+            Log.w(TAG, "got exception when reading thumbnail id=" + id + ", exception: " + ex);
         } catch (RuntimeException ex) {
             // Other NIO related exception like disk full, read only channel..etc
             Log.e(TAG, "Got exception when reading thumbnail, id = " + id +
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index b34421d..ddd4e24 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -51,15 +51,8 @@
     mAlbumArtDealer = NULL;
     mThumbnail = NULL;
     mAlbumArt = NULL;
-
-#ifndef NO_OPENCORE
-    mRetriever = new PVMetadataRetriever();
-#else
     mRetriever = NULL;
-#endif
-    if (mRetriever == NULL) {
-        LOGE("failed to initialize the retriever");
-    }
+    mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
 }
 
 MetadataRetrieverClient::~MetadataRetrieverClient()
@@ -74,7 +67,7 @@
     char buffer[SIZE];
     String8 result;
     result.append(" MetadataRetrieverClient\n");
-    snprintf(buffer, 255, "  pid(%d)\n", mPid);
+    snprintf(buffer, 255, "  pid(%d) mode(%d)\n", mPid, mMode);
     result.append(buffer);
     write(fd, result.string(), result.size());
     write(fd, "\n", 1);
@@ -90,6 +83,7 @@
     mAlbumArtDealer.clear();
     mThumbnail.clear();
     mAlbumArt.clear();
+    mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
     IPCThreadState::self()->flushCommands();
 }
 
@@ -134,7 +128,10 @@
     LOGV("player type = %d", playerType);
     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
     if (p == NULL) return NO_INIT;
-    status_t ret = p->setDataSource(url);
+    status_t ret = p->setMode(mMode);
+    if (ret == NO_ERROR) {
+        ret = p->setDataSource(url);
+    }
     if (ret == NO_ERROR) mRetriever = p;
     return ret;
 }
@@ -143,12 +140,6 @@
 {
     LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
     Mutex::Autolock lock(mLock);
-    if (mRetriever == NULL) {
-        LOGE("retriever is not initialized");
-        ::close(fd);
-        return NO_INIT;
-    }
-
     struct stat sb;
     int ret = fstat(fd, &sb);
     if (ret != 0) {
@@ -178,7 +169,10 @@
         ::close(fd);
         return NO_INIT;
     }
-    status_t status = p->setDataSource(fd, offset, length);
+    status_t status = p->setMode(mMode);
+    if (status == NO_ERROR) {
+        p->setDataSource(fd, offset, length);
+    }
     if (status == NO_ERROR) mRetriever = p;
     ::close(fd);
     return status;
@@ -188,22 +182,30 @@
 {
     LOGV("setMode");
     Mutex::Autolock lock(mLock);
-    if (mRetriever == NULL) {
-        LOGE("retriever is not initialized");
-        return NO_INIT;
+    if (mode < METADATA_MODE_NOOP ||
+        mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
+        LOGE("invalid mode %d", mode);
+        return BAD_VALUE;
     }
-    return mRetriever->setMode(mode);
+    mMode = mode;
+    return NO_ERROR;
 }
 
 status_t MetadataRetrieverClient::getMode(int* mode) const
 {
     LOGV("getMode");
     Mutex::Autolock lock(mLock);
+
+    // TODO:
+    // This may not be necessary.
+    // If setDataSource() has not been called, return the cached value
+    // otherwise, return the value retrieved from the retriever
     if (mRetriever == NULL) {
-        LOGE("retriever is not initialized");
-        return NO_INIT;
+        *mode = mMode;
+    } else {
+        mRetriever->getMode(mode);
     }
-    return mRetriever->getMode(mode);
+    return NO_ERROR;
 }
 
 sp<IMemory> MetadataRetrieverClient::captureFrame()
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 88d50bf..8cb8ad1 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -60,6 +60,7 @@
     mutable Mutex                          mLock;
     sp<MediaMetadataRetrieverBase>         mRetriever;
     pid_t                                  mPid;
+    int                                    mMode;
 
     // Keep the shared memory copy of album art and capture frame (for thumbnail)
     sp<MemoryDealer>                       mAlbumArtDealer;
diff --git a/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..aad82c5
--- /dev/null
+++ b/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/drawable/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable/ic_launcher_settings.png
index 16db056..aad82c5 100755
--- a/packages/SettingsProvider/res/drawable/ic_launcher_settings.png
+++ b/packages/SettingsProvider/res/drawable/ic_launcher_settings.png
Binary files differ
diff --git a/packages/TtsService/AndroidManifest.xml b/packages/TtsService/AndroidManifest.xml
index bd17ba0..46e0ad1 100755
--- a/packages/TtsService/AndroidManifest.xml
+++ b/packages/TtsService/AndroidManifest.xml
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.tts">
-    <application android:label="TTS Service">
+    <application android:label="TTS Service"
+        android:icon="@drawable/ic_launcher_text_to_speech">
         <service android:enabled="true"
                  android:name=".TtsService"
                  android:label="TTS Service">
diff --git a/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png b/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png
new file mode 100644
index 0000000..3d0c807
--- /dev/null
+++ b/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png
Binary files differ
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index a48900a..37e8a99 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -59,6 +59,7 @@
         CDMA_ACCESS_FAILURE,
         CDMA_PREEMPTED,
         CDMA_NOT_EMERGENCY,              /* not an emergency call */
+        CDMA_ACCESS_BLOCKED,            /* Access Blocked by CDMA network */
         ERROR_UNSPECIFIED
     }
 
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index f3b59a8..d802efa 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -2174,7 +2174,7 @@
             case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret =  responseCdmaBroadcastConfig(p); break;
             case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret =  responseVoid(p); break;
             case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret =  responseVoid(p); break;
-            case RIL_REQUEST_CDMA_VALIDATE_AKEY: ret =  responseVoid(p); break;
+            case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: ret =  responseVoid(p); break;
             case RIL_REQUEST_CDMA_SUBSCRIPTION: ret =  responseStrings(p); break;
             case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret =  responseInts(p); break;
             case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret =  responseVoid(p); break;
@@ -3197,7 +3197,7 @@
             case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG";
             case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG";
             case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: return "RIL_REQUEST_GSM_BROADCAST_ACTIVATION";
-            case RIL_REQUEST_CDMA_VALIDATE_AKEY: return "RIL_REQUEST_CDMA_VALIDATE_AKEY";
+            case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: return "RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY";
             case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: return "RIL_REQUEST_CDMA_BROADCAST_ACTIVATION";
             case RIL_REQUEST_CDMA_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SUBSCRIPTION";
             case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3e9d8ad..c29adcf 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -210,7 +210,7 @@
     int RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83;
     int RIL_REQUEST_CDMA_FLASH = 84;
     int RIL_REQUEST_CDMA_BURST_DTMF = 85;
-    int RIL_REQUEST_CDMA_VALIDATE_AKEY = 86;
+    int RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY = 86;
     int RIL_REQUEST_CDMA_SEND_SMS = 87;
     int RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE = 88;
     int RIL_REQUEST_GSM_GET_BROADCAST_CONFIG = 89;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
index fb5f0fa..ad6c23c 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
@@ -17,9 +17,10 @@
 package com.android.internal.telephony.cdma;
 
 /**
- * Call fail causes from TS 24.008 .
- * These are mostly the cause codes we need to distinguish for the UI.
- * See 22.001 Annex F.4 for mapping of cause codes to local tones.
+ * CDMA Call fail causes covering all the possible failures that are
+ * needed to be distinguished by the UI. CDMA call failure reasons
+ * are derived from the possible call failure scenarios described
+ * in "CDMA IS2000 - Release A (C.S0005-A v6.0)" standard.
  *
  * {@hide}
  *
@@ -51,5 +52,8 @@
     // For non-emergency number dialed while in emergency callback mode.
     static final int CDMA_NOT_EMERGENCY             = 1008;
 
+    // Access Blocked by CDMA Network.
+    static final int CDMA_ACCESS_BLOCKED            = 1009;
+
     static final int ERROR_UNSPECIFIED = 0xffff;
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index bc04e02..f637d33 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -418,6 +418,8 @@
                 return DisconnectCause.CDMA_PREEMPTED;
             case CallFailCause.CDMA_NOT_EMERGENCY:
                 return DisconnectCause.CDMA_NOT_EMERGENCY;
+            case CallFailCause.CDMA_ACCESS_BLOCKED:
+                return DisconnectCause.CDMA_ACCESS_BLOCKED;
             case CallFailCause.ERROR_UNSPECIFIED:
             case CallFailCause.NORMAL_CLEARING:
             default:
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 9407603..d0a9337 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -76,6 +76,9 @@
     /** Currently active CdmaDataConnection */
     private CdmaDataConnection mActiveDataConnection;
 
+    /** mimic of GSM's mActiveApn */
+    private boolean mIsApnActive = false;
+
     private boolean mPendingRestartRadio = false;
     private static final int TIME_DELAYED_TO_RESTART_RADIO =
             SystemProperties.getInt("ro.cdma.timetoradiorestart", 20000);
@@ -245,8 +248,7 @@
 
     @Override
     protected boolean isApnTypeActive(String type) {
-        return (isApnTypeAvailable(type) &&
-                (state != State.IDLE));
+        return (mIsApnActive && isApnTypeAvailable(type));
     }
 
     @Override
@@ -260,10 +262,15 @@
     }
 
     protected String[] getActiveApnTypes() {
-        if (state != State.IDLE) {
-            return mSupportedApnTypes.clone();
+        String[] result;
+        if (mIsApnActive) {
+            result = mSupportedApnTypes.clone();
+        } else {
+            // TODO - should this return an empty array?  See GSM too.
+            result = new String[1];
+            result[0] = Phone.APN_TYPE_DEFAULT;
         }
-        return new String[0];
+        return result;
     }
 
     protected String getActiveApnString() {
@@ -386,6 +393,7 @@
         if (!tearDown) {
             setState(State.IDLE);
             phone.notifyDataConnection(reason);
+            mIsApnActive = false;
         }
     }
 
@@ -409,6 +417,7 @@
         }
 
         mActiveDataConnection = conn;
+        mIsApnActive = true;
 
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
@@ -742,6 +751,7 @@
         }
 
         phone.notifyDataConnection(reason);
+        mIsApnActive = false;
         if (retryAfterDisconnected(reason)) {
           trySetupData(reason);
       }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index c85b9bd..5bdf09f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -596,32 +596,36 @@
     }
 
     protected String getInterfaceName(String apnType) {
-        if (mActivePdp != null
-                && (apnType == null || mActiveApn.canHandleType(apnType))) {
+        if (mActivePdp != null &&
+                (apnType == null ||
+                (mActiveApn != null && mActiveApn.canHandleType(apnType)))) {
             return mActivePdp.getInterface();
         }
         return null;
     }
 
     protected String getIpAddress(String apnType) {
-        if (mActivePdp != null
-                && (apnType == null || mActiveApn.canHandleType(apnType))) {
+        if (mActivePdp != null &&
+                (apnType == null ||
+                (mActiveApn != null && mActiveApn.canHandleType(apnType)))) {
             return mActivePdp.getIpAddress();
         }
         return null;
     }
 
     public String getGateway(String apnType) {
-        if (mActivePdp != null
-                && (apnType == null || mActiveApn.canHandleType(apnType))) {
+        if (mActivePdp != null &&
+                (apnType == null ||
+                (mActiveApn != null && mActiveApn.canHandleType(apnType)))) {
             return mActivePdp.getGatewayAddress();
         }
         return null;
     }
 
     protected String[] getDnsServers(String apnType) {
-        if (mActivePdp != null
-                && (apnType == null || mActiveApn.canHandleType(apnType))) {
+        if (mActivePdp != null &&
+                (apnType == null ||
+                (mActiveApn != null && mActiveApn.canHandleType(apnType)))) {
             return mActivePdp.getDnsServers();
         }
         return null;