Merge change I272af007 into eclair-mr2

* changes:
  a possible fix for the bug http://b/issue?id=2200637
diff --git a/Android.mk b/Android.mk
index a40d3f9..f538d8e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -209,6 +209,7 @@
 	frameworks/base/core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
 	frameworks/base/core/java/android/app/Notification.aidl \
 	frameworks/base/core/java/android/app/PendingIntent.aidl \
+	frameworks/base/core/java/android/bluetooth/BluetoothDevice.aidl \
 	frameworks/base/core/java/android/content/ComponentName.aidl \
 	frameworks/base/core/java/android/content/Intent.aidl \
 	frameworks/base/core/java/android/content/IntentSender.aidl \
diff --git a/api/5.xml b/api/5.xml
index 6148047..73df0cb 100644
--- a/api/5.xml
+++ b/api/5.xml
@@ -162357,17 +162357,6 @@
  visibility="protected"
 >
 </field>
-<field name="FLAG_USE_CHILD_DRAWING_ORDER"
- type="int"
- transient="false"
- volatile="false"
- value="1024"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="protected"
->
-</field>
 <field name="FOCUS_AFTER_DESCENDANTS"
  type="int"
  transient="false"
diff --git a/api/current.xml b/api/current.xml
index c84f13e..7df3192 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -162753,6 +162753,17 @@
  visibility="public"
 >
 </method>
+<method name="isChildrenDrawingOrderEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
 <method name="isChildrenDrawnWithCacheEnabled"
  return="boolean"
  abstract="false"
@@ -163136,6 +163147,19 @@
 <parameter name="enabled" type="boolean">
 </parameter>
 </method>
+<method name="setChildrenDrawingOrderEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
 <method name="setChildrenDrawnWithCacheEnabled"
  return="void"
  abstract="false"
@@ -163303,17 +163327,6 @@
  visibility="protected"
 >
 </field>
-<field name="FLAG_USE_CHILD_DRAWING_ORDER"
- type="int"
- transient="false"
- volatile="false"
- value="1024"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="protected"
->
-</field>
 <field name="FOCUS_AFTER_DESCENDANTS"
  type="int"
  transient="false"
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
index 594c0e8..34f30a7 100755
--- a/core/java/android/os/IHardwareService.aidl
+++ b/core/java/android/os/IHardwareService.aidl
@@ -1,16 +1,16 @@
 /**
  * Copyright (c) 2007, The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
+ * 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 
+ *     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 
+ * 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.
  */
 
@@ -23,13 +23,13 @@
     void vibrate(long milliseconds, IBinder token);
     void vibratePattern(in long[] pattern, int repeat, IBinder token);
     void cancelVibrate(IBinder token);
-    
+
     // flashlight support
     boolean getFlashlightEnabled();
     void setFlashlightEnabled(boolean on);
     void enableCameraFlash(int milliseconds);
 
     // for the phone
-    void setAttentionLight(boolean on);
+    void setAttentionLight(boolean on, int color);
 }
 
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
index cab9dc1..f01659e8 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -471,20 +471,24 @@
         }
         StringBuilder builder = new StringBuilder();
         String trimed = data.trim();
-        int length = trimed.length();
-        for (int i = 0; i < length; i++) {
-            char ch = trimed.charAt(i);
-            if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
-                builder.append(ch);
+        final String formattedNumber;
+        if (type == Phone.TYPE_PAGER) {
+            formattedNumber = trimed;
+        } else {
+            final int length = trimed.length();
+            for (int i = 0; i < length; i++) {
+                char ch = trimed.charAt(i);
+                if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
+                    builder.append(ch);
+                }
             }
-        }
 
-        // Use NANP in default when there's no information about locale.
-        final int formattingType = (VCardConfig.isJapaneseDevice(mVCardType) ?
-                PhoneNumberUtils.FORMAT_JAPAN : PhoneNumberUtils.FORMAT_NANP);
-        final String formattedPhoneNumber =
-                PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
-        PhoneData phoneData = new PhoneData(type, formattedPhoneNumber, label, isPrimary);
+            // Use NANP in default when there's no information about locale.
+            final int formattingType = (VCardConfig.isJapaneseDevice(mVCardType) ?
+                    PhoneNumberUtils.FORMAT_JAPAN : PhoneNumberUtils.FORMAT_NANP);
+            formattedNumber = PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
+        }
+        PhoneData phoneData = new PhoneData(type, formattedNumber, label, isPrimary);
         mPhoneList.add(phoneData);
     }
 
@@ -726,8 +730,8 @@
                 // which is correct behavior from the view of vCard 2.1.
                 // But we want it to be separated, so do the separation here.
                 final List<String> phoneticNameList =
-                    VCardUtils.constructListFromValue(propValue,    
-                            VCardConfig.isV30(mVCardType));
+                        VCardUtils.constructListFromValue(propValue,
+                                VCardConfig.isV30(mVCardType));
                 handlePhoneticNameFromSound(phoneticNameList);
             } else {
                 // Ignore this field since Android cannot understand what it is.
@@ -856,7 +860,8 @@
             }
         } else if (propName.equals(Constants.PROPERTY_TEL)) {
             final Collection<String> typeCollection = paramMap.get(Constants.PARAM_TYPE);
-            final Object typeObject = VCardUtils.getPhoneTypeFromStrings(typeCollection);
+            final Object typeObject =
+                VCardUtils.getPhoneTypeFromStrings(typeCollection, propValue);
             final int type;
             final String label;
             if (typeObject instanceof Integer) {
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index b8f4cfd..9d72c5f 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -53,6 +53,7 @@
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -144,6 +145,7 @@
     private static final String VCARD_PARAM_ENCODING_BASE64_V30 = "ENCODING=b";
 
     private static final String SHIFT_JIS = "SHIFT_JIS";
+    private static final String UTF_8 = "UTF-8";
 
     /**
      * Special URI for testing.
@@ -359,12 +361,9 @@
         mIsV30 = VCardConfig.isV30(vcardType);
         mUsesQuotedPrintable = VCardConfig.usesQuotedPrintable(vcardType);
         mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
-        mIsJapaneseMobilePhone = VCardConfig
-                .needsToConvertPhoneticString(vcardType);
-        mOnlyOneNoteFieldIsAvailable = VCardConfig
-                .onlyOneNoteFieldIsAvailable(vcardType);
-        mUsesAndroidProperty = VCardConfig
-                .usesAndroidSpecificProperty(vcardType);
+        mIsJapaneseMobilePhone = VCardConfig.needsToConvertPhoneticString(vcardType);
+        mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType);
+        mUsesAndroidProperty = VCardConfig.usesAndroidSpecificProperty(vcardType);
         mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
         mUsesUtf8 = VCardConfig.usesUtf8(vcardType);
         mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
@@ -374,17 +373,31 @@
         mHandlerList = new ArrayList<OneEntryHandler>();
 
         if (mIsDoCoMo) {
-            mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
+            String charset;
+            try {
+                charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
+            } catch (UnsupportedCharsetException e) {
+                Log.e(LOG_TAG, "DoCoMo-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
+                charset = SHIFT_JIS;
+            }
+            mCharsetString = charset;
             // Do not use mCharsetString bellow since it is different from "SHIFT_JIS" but
             // may be "DOCOMO_SHIFT_JIS" or something like that (internal expression used in
             // Android, not shown to the public).
             mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
         } else if (mUsesShiftJis) {
-            mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
+            String charset;
+            try {
+                charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
+            } catch (UnsupportedCharsetException e) {
+                Log.e(LOG_TAG, "Vendor-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
+                charset = SHIFT_JIS;
+            }
+            mCharsetString = charset;
             mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
         } else {
-            mCharsetString = "UTF-8";
-            mVCardCharsetParameter = "CHARSET=UTF-8";
+            mCharsetString = UTF_8;
+            mVCardCharsetParameter = "CHARSET=" + UTF_8;
         }
     }
 
@@ -702,34 +715,46 @@
             }
         }
 
-        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);
+        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);
 
         if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
+            final boolean shouldAppendCharsetParameterToName =
+                !(mIsV30 && UTF_8.equalsIgnoreCase(mCharsetString)) &&
+                shouldAppendCharsetParameters(Arrays.asList(
+                        familyName, givenName, middleName, prefix, suffix));
+            final boolean reallyUseQuotedPrintableToName =
+                    (!mRefrainsQPToPrimaryProperties &&
+                            !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) &&
+                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) &&
+                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) &&
+                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(prefix) &&
+                                    VCardUtils.containsOnlyNonCrLfPrintableAscii(suffix)));
+
+            final String formattedName;
+            if (!TextUtils.isEmpty(displayName)) {
+                formattedName = displayName;
+            } else {
+                formattedName = VCardUtils.constructNameFromElements(
+                        VCardConfig.getNameOrderType(mVCardType),
+                        familyName, middleName, givenName, prefix, suffix);
+            }
+            final boolean shouldAppendCharsetParameterToFN =
+                    !(mIsV30 && UTF_8.equalsIgnoreCase(mCharsetString)) &&
+                    shouldAppendCharsetParameter(formattedName);
+            final boolean reallyUseQuotedPrintableToFN =
+                    !mRefrainsQPToPrimaryProperties &&
+                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedName);
+
             final String encodedFamily;
             final String encodedGiven;
             final String encodedMiddle;
             final String encodedPrefix;
             final String encodedSuffix;
-
-            final boolean reallyUseQuotedPrintableToName =
-                (!mRefrainsQPToPrimaryProperties &&
-                    !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) &&
-                            VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) &&
-                            VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) &&
-                            VCardUtils.containsOnlyNonCrLfPrintableAscii(prefix) &&
-                            VCardUtils.containsOnlyNonCrLfPrintableAscii(suffix)));
-
             if (reallyUseQuotedPrintableToName) {
                 encodedFamily = encodeQuotedPrintable(familyName);
                 encodedGiven = encodeQuotedPrintable(givenName);
@@ -744,59 +769,61 @@
                 encodedSuffix = escapeCharacters(suffix);
             }
 
+            final String encodedFormattedname =
+                    (reallyUseQuotedPrintableToFN ?
+                            encodeQuotedPrintable(formattedName) : escapeCharacters(formattedName));
+
             builder.append(Constants.PROPERTY_N);
-            if (shouldAppendCharsetParameters(Arrays.asList(
-                    encodedFamily, encodedGiven, encodedMiddle, encodedPrefix, encodedSuffix))) {
-                builder.append(VCARD_PARAM_SEPARATOR);
-                builder.append(mVCardCharsetParameter);
-            }
-            if (reallyUseQuotedPrintableToName) {
-                builder.append(VCARD_PARAM_SEPARATOR);
-                builder.append(VCARD_PARAM_ENCODING_QP);
-            }
-
-            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_END_OF_LINE);
-
-            final String formattedName;
-            if (!TextUtils.isEmpty(displayName)) {
-                formattedName = displayName;
+            if (mIsDoCoMo) {
+                if (shouldAppendCharsetParameterToName) {
+                    builder.append(VCARD_PARAM_SEPARATOR);
+                    builder.append(mVCardCharsetParameter);
+                }
+                if (reallyUseQuotedPrintableToName) {
+                    builder.append(VCARD_PARAM_SEPARATOR);
+                    builder.append(VCARD_PARAM_ENCODING_QP);
+                }
+                builder.append(VCARD_DATA_SEPARATOR);
+                // DoCoMo phones require that all the elements in the "family name" field.
+                builder.append(formattedName);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
             } else {
-                formattedName = VCardUtils.constructNameFromElements(
-                    VCardConfig.getNameOrderType(mVCardType),
-                    encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix);
+                if (shouldAppendCharsetParameterToName) {
+                    builder.append(VCARD_PARAM_SEPARATOR);
+                    builder.append(mVCardCharsetParameter);
+                }
+                if (reallyUseQuotedPrintableToName) {
+                    builder.append(VCARD_PARAM_SEPARATOR);
+                    builder.append(VCARD_PARAM_ENCODING_QP);
+                }
+                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);
             }
-
-            final boolean reallyUseQuotedPrintableToFullname =
-                !mRefrainsQPToPrimaryProperties &&
-                !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedName);
-
-            final String encodedFullname =
-                reallyUseQuotedPrintableToFullname ?
-                        encodeQuotedPrintable(formattedName) :
-                            escapeCharacters(formattedName);
+            builder.append(VCARD_END_OF_LINE);
 
             // FN property
             builder.append(Constants.PROPERTY_FN);
-            if (shouldAppendCharsetParameter(encodedFullname)) {
+            if (shouldAppendCharsetParameterToFN) {
                 builder.append(VCARD_PARAM_SEPARATOR);
                 builder.append(mVCardCharsetParameter);
             }
-            if (reallyUseQuotedPrintableToFullname) {
+            if (reallyUseQuotedPrintableToFN) {
                 builder.append(VCARD_PARAM_SEPARATOR);
                 builder.append(VCARD_PARAM_ENCODING_QP);
             }
             builder.append(VCARD_DATA_SEPARATOR);
-            builder.append(encodedFullname);
+            builder.append(encodedFormattedname);
             builder.append(VCARD_END_OF_LINE);
         } else if (!TextUtils.isEmpty(displayName)) {
             final boolean reallyUseQuotedPrintableToDisplayName =
@@ -808,7 +835,7 @@
                                 escapeCharacters(displayName);
 
             builder.append(Constants.PROPERTY_N);
-            if (shouldAppendCharsetParameter(encodedDisplayName)) {
+            if (shouldAppendCharsetParameter(displayName)) {
                 builder.append(VCARD_PARAM_SEPARATOR);
                 builder.append(mVCardCharsetParameter);
             }
@@ -826,7 +853,7 @@
             if (mIsV30) {
                 builder.append(Constants.PROPERTY_FN);
                 // TODO: Not allowed formally...
-                if (shouldAppendCharsetParameter(encodedDisplayName)) {
+                if (shouldAppendCharsetParameter(displayName)) {
                     builder.append(VCARD_PARAM_SEPARATOR);
                     builder.append(mVCardCharsetParameter);
                 }
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
index c59e258..05e6730 100644
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -98,7 +98,11 @@
      * Returns Interger when the given types can be parsed as known type. Returns String object
      * when not, which should be set to label. 
      */
-    public static Object getPhoneTypeFromStrings(Collection<String> types) {
+    public static Object getPhoneTypeFromStrings(Collection<String> types,
+            String number) {
+        if (number == null) {
+            number = "";
+        }
         int type = -1;
         String label = null;
         boolean isFax = false;
@@ -117,7 +121,20 @@
                     }
                     Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
                     if (tmp != null) {
-                        type = tmp;
+                        final int typeCandidate = tmp;
+                        // TYPE_PAGER is prefered when the number contains @ surronded by
+                        // a pager number and a domain name.
+                        // e.g.
+                        // o 1111@domain.com
+                        // x @domain.com
+                        // x 1111@
+                        final int indexOfAt = number.indexOf("@");
+                        if ((typeCandidate == Phone.TYPE_PAGER
+                                && 0 < indexOfAt && indexOfAt < number.length() - 1)
+                                || type < 0
+                                || type == Phone.TYPE_CUSTOM) {
+                            type = tmp;
+                        }
                     } else if (type < 0) {
                         type = Phone.TYPE_CUSTOM;
                         label = typeString;
@@ -345,7 +362,7 @@
         if (TextUtils.isEmpty(str)) {
             return true;
         }
-        
+
         final int length = str.length();
         final int asciiFirst = 0x20;
         final int asciiLast = 0x126;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f7b7f02..e2f15c7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -150,6 +150,8 @@
     /**
      * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
      * to get the index of the child to draw for that iteration.
+     * 
+     * @hide
      */
     protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
 
@@ -1307,11 +1309,14 @@
      * if you want to change the drawing order of children. By default, it
      * returns i.
      * <p>
-     * NOTE: In order for this method to be called, the
-     * {@link #FLAG_USE_CHILD_DRAWING_ORDER} must be set.
+     * NOTE: In order for this method to be called, you must enable child ordering
+     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
      *
      * @param i The current iteration.
      * @return The index of the child to draw this iteration.
+     * 
+     * @see #setChildrenDrawingOrderEnabled(boolean)
+     * @see #isChildrenDrawingOrderEnabled()
      */
     protected int getChildDrawingOrder(int childCount, int i) {
         return i;
@@ -2706,6 +2711,35 @@
         setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
     }
 
+    /**
+     * Indicates whether the ViewGroup is drawing its children in the order defined by
+     * {@link #getChildDrawingOrder(int, int)}.
+     *
+     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
+     *         false otherwise
+     *
+     * @see #setChildrenDrawingOrderEnabled(boolean)
+     * @see #getChildDrawingOrder(int, int)
+     */
+    @ViewDebug.ExportedProperty
+    protected boolean isChildrenDrawingOrderEnabled() {
+        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
+    }
+
+    /**
+     * Tells the ViewGroup whether to draw its children in the order defined by the method
+     * {@link #getChildDrawingOrder(int, int)}.
+     *
+     * @param enabled true if the order of the children when drawing is determined by
+     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
+     *
+     * @see #isChildrenDrawingOrderEnabled()
+     * @see #getChildDrawingOrder(int, int)
+     */
+    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
+        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
+    }
+
     private void setBooleanFlag(int flag, boolean value) {
         if (value) {
             mGroupFlags |= flag;
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 07bb1ab..50aa967 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -79,7 +79,7 @@
 
 static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
         jint streamType, jint volume) {
-    ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume));
+    ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume), true);
 
     env->SetIntField(thiz, fields.context, 0);
 
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 503cb31..008468c 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -314,6 +314,11 @@
     };
 
             bool processAudioBuffer(const sp<ClientRecordThread>& thread);
+            status_t openRecord(uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int frameCount,
+                                uint32_t flags);
 
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
@@ -341,6 +346,7 @@
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
     audio_io_handle_t       mInput;
+    uint32_t                mFlags;
 };
 
 }; // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 981c2f6..14b30ae 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -391,6 +391,14 @@
     };
 
             bool processAudioBuffer(const sp<AudioTrackThread>& thread);
+            status_t createTrack(int streamType,
+                                 uint32_t sampleRate,
+                                 int format,
+                                 int channelCount,
+                                 int frameCount,
+                                 uint32_t flags,
+                                 const sp<IMemory>& sharedBuffer,
+                                 audio_io_handle_t output);
 
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index c884c2c..1ad1f26 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -151,7 +151,7 @@
         NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
     };
 
-    ToneGenerator(int streamType, float volume);
+    ToneGenerator(int streamType, float volume, bool threadCanCallJava = false);
     ~ToneGenerator();
 
     bool startTone(int toneType, int durationMs = -1);
@@ -242,6 +242,7 @@
 
     static const ToneDescriptor sToneDescriptors[];
 
+    bool mThreadCanCallJava;
     unsigned int mTotalSmp;  // Total number of audio samples played (gives current time)
     unsigned int mNextSegSmp;  // Position of next segment transition expressed in samples
     // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
diff --git a/media/java/android/media/ThumbnailUtil.java b/media/java/android/media/ThumbnailUtil.java
index 7c6bca3..a33adc9 100644
--- a/media/java/android/media/ThumbnailUtil.java
+++ b/media/java/android/media/ThumbnailUtil.java
@@ -35,9 +35,7 @@
 import android.media.MediaMetadataRetriever;
 import android.media.MediaFile.MediaFileType;
 
-import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
 
@@ -296,7 +294,7 @@
      * @param uri URI of original image
      * @param origId image id
      * @param kind either MINI_KIND or MICRO_KIND
-     * @param saveImage Whether to save MINI_KIND thumbnail obtained in this method.
+     * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method.
      * @return Bitmap
      */
     public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri,
@@ -306,20 +304,12 @@
                 ThumbnailUtil.THUMBNAIL_TARGET_SIZE : ThumbnailUtil.MINI_THUMB_TARGET_SIZE;
         int maxPixels = wantMini ?
                 ThumbnailUtil.THUMBNAIL_MAX_NUM_PIXELS : ThumbnailUtil.MINI_THUMB_MAX_NUM_PIXELS;
-        byte[] thumbData = null;
+        SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap();
         Bitmap bitmap = null;
         MediaFileType fileType = MediaFile.getFileType(filePath);
         if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) {
-            thumbData = createThumbnailFromEXIF(filePath, targetSize);
-        }
-
-        if (thumbData != null) {
-            BitmapFactory.Options options = new BitmapFactory.Options();
-            options.inSampleSize = computeSampleSize(options, targetSize, maxPixels);
-            options.inDither = false;
-            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-            options.inJustDecodeBounds = false;
-            bitmap = BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, options);
+            createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap);
+            bitmap = sizedThumbnailBitmap.mBitmap;
         }
 
         if (bitmap == null) {
@@ -331,9 +321,11 @@
         }
 
         if (saveMini) {
-            if (thumbData != null) {
-                ThumbnailUtil.storeThumbnail(cr, origId, thumbData, bitmap.getWidth(),
-                        bitmap.getHeight());
+            if (sizedThumbnailBitmap.mThumbnailData != null) {
+                ThumbnailUtil.storeThumbnail(cr, origId,
+                        sizedThumbnailBitmap.mThumbnailData,
+                        sizedThumbnailBitmap.mThumbnailWidth,
+                        sizedThumbnailBitmap.mThumbnailHeight);
             } else {
                 ThumbnailUtil.storeThumbnail(cr, origId, bitmap);
             }
@@ -521,31 +513,69 @@
         }
     }
 
-    // Extract thumbnail in image that meets the targetSize criteria.
-    static byte[] createThumbnailFromEXIF(String filePath, int targetSize) {
-        if (filePath == null) return null;
+    // SizedThumbnailBitmap contains the bitmap, which is downsampled either from
+    // the thumbnail in exif or the full image.
+    // mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail is not null.
+    // The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight.
+    private static class SizedThumbnailBitmap {
+        public byte[] mThumbnailData;
+        public Bitmap mBitmap;
+        public int mThumbnailWidth;
+        public int mThumbnailHeight;
+    }
 
+    // Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image.
+    // The functions returns a SizedThumbnailBitmap,
+    // which contains a downsampled bitmap and the thumbnail data in EXIF if exists.
+    private static void createThumbnailFromEXIF(String filePath, int targetSize,
+            int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) {
+        if (filePath == null) return;
+
+        ExifInterface exif = null;
+        byte [] thumbData = null;
         try {
-            ExifInterface exif = new ExifInterface(filePath);
-            if (exif == null) return null;
-            byte [] thumbData = exif.getThumbnail();
-            if (thumbData == null) return null;
-            // Sniff the size of the EXIF thumbnail before decoding it. Photos
-            // from the device will pass, but images that are side loaded from
-            // other cameras may not.
-            BitmapFactory.Options options = new BitmapFactory.Options();
-            options.inJustDecodeBounds = true;
-            BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, options);
-
-            int width = options.outWidth;
-            int height = options.outHeight;
-
-            if (width >= targetSize && height >= targetSize) {
-                return thumbData;
+            exif = new ExifInterface(filePath);
+            if (exif != null) {
+                thumbData = exif.getThumbnail();
             }
         } catch (IOException ex) {
             Log.w(TAG, ex);
         }
-        return null;
+
+        BitmapFactory.Options fullOptions = new BitmapFactory.Options();
+        BitmapFactory.Options exifOptions = new BitmapFactory.Options();
+        int exifThumbWidth = 0;
+        int fullThumbWidth = 0;
+
+        // Compute exifThumbWidth.
+        if (thumbData != null) {
+            exifOptions.inJustDecodeBounds = true;
+            BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions);
+            exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels);
+            exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize;
+        }
+
+        // Compute fullThumbWidth.
+        fullOptions.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(filePath, fullOptions);
+        fullOptions.inSampleSize = computeSampleSize(fullOptions, targetSize, maxPixels);
+        fullThumbWidth = fullOptions.outWidth / fullOptions.inSampleSize;
+
+        // Choose the larger thumbnail as the returning sizedThumbBitmap.
+        if (exifThumbWidth > fullThumbWidth) {
+            int width = exifOptions.outWidth;
+            int height = exifOptions.outHeight;
+            exifOptions.inJustDecodeBounds = false;
+            sizedThumbBitmap.mBitmap = BitmapFactory.decodeByteArray(thumbData, 0,
+                    thumbData.length, exifOptions);
+            if (sizedThumbBitmap.mBitmap != null) {
+                sizedThumbBitmap.mThumbnailData = thumbData;
+                sizedThumbBitmap.mThumbnailWidth = width;
+                sizedThumbBitmap.mThumbnailHeight = height;
+            }
+        } else {
+            fullOptions.inJustDecodeBounds = false;
+            sizedThumbBitmap.mBitmap = BitmapFactory.decodeFile(filePath, fullOptions);
+        }
     }
 }
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 5e35564..e63c0d2 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -101,11 +101,6 @@
         return INVALID_OPERATION;
     }
 
-    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
-    if (audioFlinger == 0) {
-        return NO_INIT;
-    }
-
     if (inputSource == AUDIO_SOURCE_DEFAULT) {
         inputSource = AUDIO_SOURCE_MIC;
     }
@@ -171,22 +166,14 @@
         notificationFrames = frameCount/2;
     }
 
-    // open record channel
-    status_t status;
-    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
-                                                       sampleRate, format,
-                                                       channelCount,
-                                                       frameCount,
-                                                       ((uint16_t)flags) << 16,
-                                                       &status);
-    if (record == 0) {
-        LOGE("AudioFlinger could not create record track, status: %d", status);
+    // create the IAudioRecord
+    status_t status = openRecord(sampleRate, format, channelCount,
+                                 frameCount, flags);
+
+    if (status != NO_ERROR) {
         return status;
     }
-    sp<IMemory> cblk = record->getCblk();
-    if (cblk == 0) {
-        return NO_INIT;
-    }
+
     if (cbf != 0) {
         mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
         if (mClientRecordThread == 0) {
@@ -196,11 +183,6 @@
 
     mStatus = NO_ERROR;
 
-    mAudioRecord = record;
-    mCblkMemory = cblk;
-    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
-    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-    mCblk->out = 0;
     mFormat = format;
     // Update buffer size in case it has been limited by AudioFlinger during track creation
     mFrameCount = mCblk->frameCount;
@@ -217,6 +199,7 @@
     mNewPosition = 0;
     mUpdatePeriod = 0;
     mInputSource = (uint8_t)inputSource;
+    mFlags = flags;
 
     return NO_ERROR;
 }
@@ -284,15 +267,26 @@
     if (android_atomic_or(1, &mActive) == 0) {
         ret = AudioSystem::startInput(mInput);
         if (ret == NO_ERROR) {
-            mNewPosition = mCblk->user + mUpdatePeriod;
-            mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-            mCblk->waitTimeMs = 0;
-            if (t != 0) {
-               t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
-            } else {
-                setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
-            }
             ret = mAudioRecord->start();
+            if (ret == DEAD_OBJECT) {
+                LOGV("start() dead IAudioRecord: creating a new one");
+                ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
+                        mFrameCount, mFlags);
+            }
+            if (ret == NO_ERROR) {
+                mNewPosition = mCblk->user + mUpdatePeriod;
+                mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+                mCblk->waitTimeMs = 0;
+                if (t != 0) {
+                   t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+                } else {
+                    setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+                }
+            } else {
+                LOGV("start() failed");
+                AudioSystem::stopInput(mInput);
+                android_atomic_and(~1, &mActive);
+            }
         }
     }
 
@@ -396,10 +390,48 @@
 
 // -------------------------------------------------------------------------
 
+status_t AudioRecord::openRecord(
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags)
+{
+    status_t status;
+    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+    if (audioFlinger == 0) {
+        return NO_INIT;
+    }
+
+    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
+                                                       sampleRate, format,
+                                                       channelCount,
+                                                       frameCount,
+                                                       ((uint16_t)flags) << 16,
+                                                       &status);
+    if (record == 0) {
+        LOGE("AudioFlinger could not create record track, status: %d", status);
+        return status;
+    }
+    sp<IMemory> cblk = record->getCblk();
+    if (cblk == 0) {
+        LOGE("Could not get control block");
+        return NO_INIT;
+    }
+    mAudioRecord.clear();
+    mAudioRecord = record;
+    mCblkMemory.clear();
+    mCblkMemory = cblk;
+    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->out = 0;
+
+    return NO_ERROR;
+}
+
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
     int active;
-    int timeout = 0;
     status_t result;
     audio_track_cblk_t* cblk = mCblk;
     uint32_t framesReq = audioBuffer->frameCount;
@@ -411,25 +443,40 @@
     uint32_t framesReady = cblk->framesReady();
 
     if (framesReady == 0) {
-        Mutex::Autolock _l(cblk->lock);
+        cblk->lock.lock();
         goto start_loop_here;
         while (framesReady == 0) {
             active = mActive;
-            if (UNLIKELY(!active))
+            if (UNLIKELY(!active)) {
+                cblk->lock.unlock();
                 return NO_MORE_BUFFERS;
-            if (UNLIKELY(!waitCount))
+            }
+            if (UNLIKELY(!waitCount)) {
+                cblk->lock.unlock();
                 return WOULD_BLOCK;
-            timeout = 0;
+            }
             result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
             if (__builtin_expect(result!=NO_ERROR, false)) {
                 cblk->waitTimeMs += waitTimeMs;
                 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
                     LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
                             "user=%08x, server=%08x", cblk->user, cblk->server);
-                    timeout = 1;
+                    cblk->lock.unlock();
+                    result = mAudioRecord->start();
+                    if (result == DEAD_OBJECT) {
+                        LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
+                        result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
+                                            mFrameCount, mFlags);
+                        if (result == NO_ERROR) {
+                            cblk = mCblk;
+                            cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+                        }
+                    }
+                    cblk->lock.lock();
                     cblk->waitTimeMs = 0;
                 }
                 if (--waitCount == 0) {
+                    cblk->lock.unlock();
                     return TIMED_OUT;
                 }
             }
@@ -437,13 +484,9 @@
         start_loop_here:
             framesReady = cblk->framesReady();
         }
+        cblk->lock.unlock();
     }
 
-    LOGW_IF(timeout,
-        "*** SERIOUS WARNING *** obtainBuffer() timed out "
-        "but didn't need to be locked. We recovered, but "
-        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
-
     cblk->waitTimeMs = 0;
 
     if (framesReq > framesReady) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 4b9d272..8529a8e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -122,11 +122,6 @@
         return INVALID_OPERATION;
     }
 
-    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
-    if (audioFlinger == 0) {
-       LOGE("Could not get audioflinger");
-       return NO_INIT;
-    }
     int afSampleRate;
     if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
         return NO_INIT;
@@ -217,28 +212,16 @@
         }
     }
 
-    // create the track
-    status_t status;
-    sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
-                                                      streamType,
-                                                      sampleRate,
-                                                      format,
-                                                      channelCount,
-                                                      frameCount,
-                                                      ((uint16_t)flags) << 16,
-                                                      sharedBuffer,
-                                                      output,
-                                                      &status);
+    mVolume[LEFT] = 1.0f;
+    mVolume[RIGHT] = 1.0f;
+    // create the IAudioTrack
+    status_t status = createTrack(streamType, sampleRate, format, channelCount,
+                                  frameCount, flags, sharedBuffer, output);
 
-    if (track == 0) {
-        LOGE("AudioFlinger could not create track, status: %d", status);
+    if (status != NO_ERROR) {
         return status;
     }
-    sp<IMemory> cblk = track->getCblk();
-    if (cblk == 0) {
-        LOGE("Could not get control block");
-        return NO_INIT;
-    }
+
     if (cbf != 0) {
         mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
         if (mAudioTrackThread == 0) {
@@ -249,22 +232,6 @@
 
     mStatus = NO_ERROR;
 
-    mAudioTrack = track;
-    mCblkMemory = cblk;
-    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
-    mCblk->out = 1;
-    // Update buffer size in case it has been limited by AudioFlinger during track creation
-    mFrameCount = mCblk->frameCount;
-    if (sharedBuffer == 0) {
-        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-    } else {
-        mCblk->buffers = sharedBuffer->pointer();
-         // Force buffer full condition as data is already present in shared memory
-        mCblk->stepUser(mFrameCount);
-    }
-    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
-    mVolume[LEFT] = 1.0f;
-    mVolume[RIGHT] = 1.0f;
     mStreamType = streamType;
     mFormat = format;
     mChannels = channels;
@@ -351,16 +318,27 @@
      }
 
     if (android_atomic_or(1, &mActive) == 0) {
-        AudioSystem::startOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
-        mNewPosition = mCblk->server + mUpdatePeriod;
-        mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
-        mCblk->waitTimeMs = 0;
-        if (t != 0) {
-           t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
-        } else {
-            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+        audio_io_handle_t output = AudioTrack::getOutput();
+        status_t status = mAudioTrack->start();
+        if (status == DEAD_OBJECT) {
+            LOGV("start() dead IAudioTrack: creating a new one");
+            status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
+                                 mFrameCount, mFlags, mSharedBuffer, output);
         }
-        mAudioTrack->start();
+        if (status == NO_ERROR) {
+            AudioSystem::startOutput(output, (AudioSystem::stream_type)mStreamType);
+            mNewPosition = mCblk->server + mUpdatePeriod;
+            mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+            mCblk->waitTimeMs = 0;
+            if (t != 0) {
+               t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
+            } else {
+                setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+            }
+        } else {
+            LOGV("start() failed");
+            android_atomic_and(~1, &mActive);
+        }
     }
 
     if (t != 0) {
@@ -617,10 +595,67 @@
 
 // -------------------------------------------------------------------------
 
+status_t AudioTrack::createTrack(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        const sp<IMemory>& sharedBuffer,
+        audio_io_handle_t output)
+{
+    status_t status;
+    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+    if (audioFlinger == 0) {
+       LOGE("Could not get audioflinger");
+       return NO_INIT;
+    }
+
+    sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
+                                                      streamType,
+                                                      sampleRate,
+                                                      format,
+                                                      channelCount,
+                                                      frameCount,
+                                                      ((uint16_t)flags) << 16,
+                                                      sharedBuffer,
+                                                      output,
+                                                      &status);
+
+    if (track == 0) {
+        LOGE("AudioFlinger could not create track, status: %d", status);
+        return status;
+    }
+    sp<IMemory> cblk = track->getCblk();
+    if (cblk == 0) {
+        LOGE("Could not get control block");
+        return NO_INIT;
+    }
+    mAudioTrack.clear();
+    mAudioTrack = track;
+    mCblkMemory.clear();
+    mCblkMemory = cblk;
+    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+    mCblk->out = 1;
+    // Update buffer size in case it has been limited by AudioFlinger during track creation
+    mFrameCount = mCblk->frameCount;
+    if (sharedBuffer == 0) {
+        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    } else {
+        mCblk->buffers = sharedBuffer->pointer();
+         // Force buffer full condition as data is already present in shared memory
+        mCblk->stepUser(mFrameCount);
+    }
+
+    mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000);
+
+    return NO_ERROR;
+}
+
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
     int active;
-    int timeout = 0;
     status_t result;
     audio_track_cblk_t* cblk = mCblk;
     uint32_t framesReq = audioBuffer->frameCount;
@@ -632,17 +667,20 @@
     uint32_t framesAvail = cblk->framesAvailable();
 
     if (framesAvail == 0) {
-        Mutex::Autolock _l(cblk->lock);
+        cblk->lock.lock();
         goto start_loop_here;
         while (framesAvail == 0) {
             active = mActive;
             if (UNLIKELY(!active)) {
                 LOGV("Not active and NO_MORE_BUFFERS");
+                cblk->lock.unlock();
                 return NO_MORE_BUFFERS;
             }
-            if (UNLIKELY(!waitCount))
+            if (UNLIKELY(!waitCount)) {
+                cblk->lock.unlock();
                 return WOULD_BLOCK;
-            timeout = 0;
+            }
+
             result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
             if (__builtin_expect(result!=NO_ERROR, false)) {
                 cblk->waitTimeMs += waitTimeMs;
@@ -654,14 +692,23 @@
                                 "user=%08x, server=%08x", this, cblk->user, cblk->server);
                         //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
                         cblk->lock.unlock();
-                        mAudioTrack->start();
+                        result = mAudioTrack->start();
+                        if (result == DEAD_OBJECT) {
+                            LOGW("obtainBuffer() dead IAudioTrack: creating a new one");
+                            result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,
+                                                 mFrameCount, mFlags, mSharedBuffer, getOutput());
+                            if (result == NO_ERROR) {
+                                cblk = mCblk;
+                                cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+                            }
+                        }
                         cblk->lock.lock();
-                        timeout = 1;
                     }
                     cblk->waitTimeMs = 0;
                 }
 
                 if (--waitCount == 0) {
+                    cblk->lock.unlock();
                     return TIMED_OUT;
                 }
             }
@@ -669,6 +716,7 @@
         start_loop_here:
             framesAvail = cblk->framesAvailable_l();
         }
+        cblk->lock.unlock();
     }
 
     cblk->waitTimeMs = 0;
@@ -684,11 +732,6 @@
         framesReq = bufferEnd - u;
     }
 
-    LOGW_IF(timeout,
-        "*** SERIOUS WARNING *** obtainBuffer() timed out "
-        "but didn't need to be locked. We recovered, but "
-        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
-
     audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
     audioBuffer->channelCount = mChannelCount;
     audioBuffer->frameCount = framesReq;
@@ -991,7 +1034,7 @@
         // Mark that we have read the first buffer so that next time stepUser() is called
         // we switch to normal obtainBuffer() timeout period
         if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
-            bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
+            bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS - 1;
         }
         // It is possible that we receive a flush()
         // while the mixer is processing a block: in this case,
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index dacf75a..ba0d55b 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -15,6 +15,10 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "IAudioRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -42,8 +46,13 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
-        remote()->transact(START, data, &reply);
-        return reply.readInt32();
+        status_t status = remote()->transact(START, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        } else {
+            LOGW("start() error: %s", strerror(-status));
+        }
+        return status;
     }
     
     virtual void stop()
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 7f43347..01ffd75 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -15,6 +15,10 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "IAudioTrack"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -45,8 +49,13 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
-        remote()->transact(START, data, &reply);
-        return reply.readInt32();
+        status_t status = remote()->transact(START, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        } else {
+            LOGW("start() error: %s", strerror(-status));
+        }
+        return status;
     }
     
     virtual void stop()
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 91d0d00..60e3d71 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -798,7 +798,7 @@
 //        none
 //
 ////////////////////////////////////////////////////////////////////////////////
-ToneGenerator::ToneGenerator(int streamType, float volume) {
+ToneGenerator::ToneGenerator(int streamType, float volume, bool threadCanCallJava) {
 
     LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
 
@@ -808,6 +808,7 @@
         LOGE("Unable to marshal AudioFlinger");
         return;
     }
+    mThreadCanCallJava = threadCanCallJava;
     mStreamType = streamType;
     mVolume = volume;
     mpAudioTrack = 0;
@@ -1015,15 +1016,25 @@
     }
 
    // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
-    mpAudioTrack
-            = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, AudioSystem::CHANNEL_OUT_MONO, 0, 0, audioCallback, this, 0);
-
+    mpAudioTrack = new AudioTrack();
     if (mpAudioTrack == 0) {
         LOGE("AudioTrack allocation failed");
         goto initAudioTrack_exit;
     }
     LOGV("Create Track: %p\n", mpAudioTrack);
 
+    mpAudioTrack->set(mStreamType,
+                      0,
+                      AudioSystem::PCM_16_BIT,
+                      AudioSystem::CHANNEL_OUT_MONO,
+                      0,
+                      0,
+                      audioCallback,
+                      this,
+                      0,
+                      0,
+                      mThreadCanCallJava);
+
     if (mpAudioTrack->initCheck() != NO_ERROR) {
         LOGE("AudioTrack->initCheck failed");
         goto initAudioTrack_exit;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 754e6e5..c3b591e 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1260,9 +1260,20 @@
 
     // ----- Restore handling -----
 
-    private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
+    private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
+        // If the target resides on the system partition, we allow it to restore
+        // data from the like-named package in a restore set even if the signatures
+        // do not match.  (Unlike general applications, those flashed to the system
+        // partition will be signed with the device's platform certificate, so on
+        // different phones the same system app will have different signatures.)
+        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+            if (DEBUG) Log.v(TAG, "System app " + target.packageName + " - skipping sig check");
+            return true;
+        }
+
         // Allow unsigned apps, but not signed on one device and unsigned on the other
         // !!! TODO: is this the right policy?
+        Signature[] deviceSigs = target.signatures;
         if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
                 + " device=" + deviceSigs);
         if ((storedSigs == null || storedSigs.length == 0)
@@ -1465,7 +1476,7 @@
                         continue;
                     }
 
-                    if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
+                    if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
                         Log.w(TAG, "Signature mismatch restoring " + packageName);
                         EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
                                 "Signature mismatch");
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index b1d58ce..3e3cf06 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -52,6 +52,7 @@
 
     static final int LIGHT_FLASH_NONE = 0;
     static final int LIGHT_FLASH_TIMED = 1;
+    static final int LIGHT_FLASH_HARDWARE = 2;
 
     private final LinkedList<Vibration> mVibrations;
     private Vibration mCurrentVibration;
@@ -125,7 +126,7 @@
         mVibrations = new LinkedList<Vibration>();
 
         mBatteryStats = BatteryStatsService.getService();
-        
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         context.registerReceiver(mIntentReceiver, filter);
@@ -239,15 +240,15 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
-    
+
     public boolean getFlashlightEnabled() {
         return Hardware.getFlashlightEnabled();
     }
-    
+
     public void setFlashlightEnabled(boolean on) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) 
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
                 != PackageManager.PERMISSION_GRANTED &&
-                mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 
+                mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
         }
@@ -255,9 +256,9 @@
     }
 
     public void enableCameraFlash(int milliseconds) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA) 
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
                 != PackageManager.PERMISSION_GRANTED &&
-                mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 
+                mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
         }
@@ -282,13 +283,13 @@
         setLight_native(mNativePointer, light, color, mode, onMS, offMS);
     }
 
-    public void setAttentionLight(boolean on) {
+    public void setAttentionLight(boolean on, int color) {
         // Not worthy of a permission.  We shouldn't have a flashlight permission.
         synchronized (this) {
             mAttentionLightOn = on;
             mPulsing = false;
-            setLight_native(mNativePointer, LIGHT_ID_ATTENTION, on ? 0xffffffff : 0,
-                    LIGHT_FLASH_NONE, 0, 0);
+            setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color,
+                    LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0);
         }
     }
 
@@ -302,8 +303,8 @@
             }
             if (!mAttentionLightOn && !mPulsing) {
                 mPulsing = true;
-                setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0xff101010,
-                        LIGHT_FLASH_NONE, 0, 0);
+                setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff,
+                        LIGHT_FLASH_HARDWARE, 7, 0);
                 mH.sendMessageDelayed(Message.obtain(mH, 1), 3000);
             }
         }
@@ -391,7 +392,7 @@
     private class VibrateThread extends Thread {
         final Vibration mVibration;
         boolean mDone;
-    
+
         VibrateThread(Vibration vib) {
             mVibration = vib;
             mWakeLock.acquire();
@@ -425,7 +426,7 @@
                 long duration = 0;
 
                 while (!mDone) {
-                    // add off-time duration to any accumulated on-time duration 
+                    // add off-time duration to any accumulated on-time duration
                     if (index < len) {
                         duration += pattern[index++];
                     }
@@ -478,7 +479,7 @@
             }
         }
     };
-    
+
     private static native int init_native();
     private static native void finalize_native(int ptr);
 
@@ -489,7 +490,7 @@
     private final PowerManager.WakeLock mWakeLock;
 
     private final IBatteryStats mBatteryStats;
-    
+
     volatile VibrateThread mThread;
 
     private int mNativePointer;
diff --git a/tests/AndroidTests/res/raw/v30_comma_separated.vcf b/tests/AndroidTests/res/raw/v30_comma_separated.vcf
new file mode 100644
index 0000000..98a7f20
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v30_comma_separated.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD

+VERSION:3.0

+N:F;G;M;;

+TEL;TYPE=PAGER,WORK,MSG:6101231234@pagersample.com

+END:VCARD

diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
index 933ff2a..917b18e 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
@@ -125,22 +125,18 @@
     }
 
     public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
+            ContentValues contentValues) {
+        return addNodeWithOrder(propName, propValue, null, null, contentValues, null, null);
+    }
+
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> propValueList) {
         return addNodeWithOrder(propName, propValue, propValueList, null, null, null, null);
     }
 
     public PropertyNodesVerifierElem addNodeWithOrder(String propName, List<String> propValueList) {
-        StringBuffer buffer = new StringBuffer();
-        boolean first = true;
-        for (String propValueElem : propValueList) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(';');
-            }
-            buffer.append(propValueElem);
-        }
-        return addNodeWithOrder(propName, buffer.toString(), propValueList,
+        final String propValue = concatinateListWithSemiColon(propValueList);
+        return addNodeWithOrder(propName, propValue.toString(), propValueList,
                 null, null, null, null);
     }
 
@@ -149,6 +145,13 @@
         return addNodeWithOrder(propName, propValue, null, null, null, paramMap_TYPE, null);
     }
 
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName,
+            List<String> propValueList, TypeSet paramMap_TYPE) {
+        final String propValue = concatinateListWithSemiColon(propValueList);
+        return addNodeWithOrder(propName, propValue, propValueList, null, null,
+                paramMap_TYPE, null);
+    }
+
     public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> propValueList, TypeSet paramMap_TYPE) {
         return addNodeWithOrder(propName, propValue, propValueList, null, null,
@@ -177,22 +180,18 @@
     }
 
     public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
+            ContentValues contentValues) {
+        return addNodeWithoutOrder(propName, propValue, null, null, contentValues, null, null);
+    }
+
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> propValueList) {
         return addNodeWithoutOrder(propName, propValue, propValueList, null, null, null, null);
     }
 
     public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, List<String> propValueList) {
-        StringBuffer buffer = new StringBuffer();
-        boolean first = true;
-        for (String propValueElem : propValueList) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(';');
-            }
-            buffer.append(propValueElem);
-        }
-        return addNodeWithoutOrder(propName, buffer.toString(), propValueList,
+        final String propValue = concatinateListWithSemiColon(propValueList);
+        return addNodeWithoutOrder(propName, propValue, propValueList,
                 null, null, null, null);
     }
 
@@ -201,6 +200,13 @@
         return addNodeWithoutOrder(propName, propValue, null, null, null, paramMap_TYPE, null);
     }
 
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName,
+            List<String> propValueList, TypeSet paramMap_TYPE) {
+        final String propValue = concatinateListWithSemiColon(propValueList);
+        return addNodeWithoutOrder(propName, propValue, propValueList, null, null,
+                paramMap_TYPE, null);
+    }
+
     public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> propValueList, TypeSet paramMap_TYPE) {
         return addNodeWithoutOrder(propName, propValue, propValueList, null, null,
@@ -291,6 +297,21 @@
         }
     }
 
+    private String concatinateListWithSemiColon(List<String> array) {
+        StringBuffer buffer = new StringBuffer();
+        boolean first = true;
+        for (String propValueElem : array) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(';');
+            }
+            buffer.append(propValueElem);
+        }
+
+        return buffer.toString();
+    }
+
     private boolean tryFoundExpectedNodeFromUnorderedList(PropertyNode actualNode,
             List<PropertyNode> expectedButDifferentValueList) {
         final String propName = actualNode.propName;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
index 1aa334a..169ea71 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
@@ -16,9 +16,7 @@
 
 package com.android.unit_tests.vcard;
 
-import android.content.ContentValues;
 import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardParser_V21;
 import android.pim.vcard.exception.VCardException;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -35,7 +33,6 @@
 import com.android.unit_tests.vcard.PropertyNodesVerifierElem.TypeSet;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.Arrays;
 
 public class VCardImporterTests extends VCardTestsBase {
@@ -571,10 +568,6 @@
      * Tests all the properties in a complicated vCard are correctly parsed by the VCardParser.
      */
     public void testV21ComplicatedCase_Parsing() throws IOException, VCardException {
-        ContentValues contentValuesForQP = new ContentValues();
-        contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
-        ContentValues contentValuesForPhoto = new ContentValues();
-        contentValuesForPhoto.put("ENCODING", "BASE64");
         PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
         verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
@@ -598,7 +591,7 @@
                                 null, null, new TypeSet("WORK"), null)
                 .addNodeWithOrder("LABEL",
                         "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited  States of America",
-                        null, null, contentValuesForQP, new TypeSet("WORK"), null)
+                        null, null, mContentValuesForQP, new TypeSet("WORK"), null)
                 .addNodeWithOrder("ADR",
                         ";;42 Plantation St.;Baytown;LA;30314;United States of America",
                         Arrays.asList("", "", "42 Plantation St.", "Baytown",
@@ -606,7 +599,7 @@
                                 new TypeSet("HOME"), null)
                 .addNodeWithOrder("LABEL",
                         "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited  States of America",
-                        null, null, contentValuesForQP,
+                        null, null, mContentValuesForQP,
                         new TypeSet("HOME"), null)
                 .addNodeWithOrder("EMAIL", "forrestgump@walladalla.com",
                         new TypeSet("PREF", "INTERNET"))
@@ -614,9 +607,9 @@
                 .addNodeWithOrder("NOTE", "The following note is the example from RFC 2045.")
                 .addNodeWithOrder("NOTE",
                         "Now's the time for all folk to come to the aid of their country.",
-                        null, null, contentValuesForQP, null, null)
+                        null, null, mContentValuesForQP, null, null)
                 .addNodeWithOrder("PHOTO", null,
-                        null, sPhotoByteArrayForComplicatedCase, contentValuesForPhoto,
+                        null, sPhotoByteArrayForComplicatedCase, mContentValuesForBase64V21,
                         new TypeSet("JPEG"), null)
                 .addNodeWithOrder("X-ATTRIBUTE", "Some String")
                 .addNodeWithOrder("BDAY", "19800101")
@@ -764,17 +757,15 @@
         // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
         // vCard 2.1/3.0 specification does not allow multiple values.
         // Do not need to handle it as multiple values.
-        ContentValues contentValuesForShiftJis = new ContentValues();
-        contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
         PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
         verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1", null, null, null, null, null)
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
-                        null, contentValuesForShiftJis, null, null)
+                        null, mContentValuesForSJis, null, null)
                 .addNodeWithOrder("SOUND",
                         "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
-                        null, null, contentValuesForShiftJis,
+                        null, null, mContentValuesForSJis,
                         new TypeSet("X-IRMC-N"), null)
                 .addNodeWithOrder("TEL", "0300000000", null, null, null,
                         new TypeSet("VOICE", "PREF"), null);
@@ -831,23 +822,18 @@
     }
 
     public void testV21Japanese2_Parsing() throws IOException, VCardException {
-        ContentValues contentValuesForShiftJis = new ContentValues();
-        contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
-        ContentValues contentValuesForQPAndSJ = new ContentValues();
-        contentValuesForQPAndSJ.put("ENCODING", "QUOTED-PRINTABLE");
-        contentValuesForQPAndSJ.put("CHARSET", "SHIFT_JIS");
         PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
         verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
                         Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
                                 "", "", ""),
-                        null, contentValuesForShiftJis, null, null)
+                        null, mContentValuesForSJis, null, null)
                 .addNodeWithOrder("FN", "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
-                        null, null, contentValuesForShiftJis, null, null)
+                        null, null, mContentValuesForSJis, null, null)
                 .addNodeWithOrder("SOUND",
                         "\uFF71\uFF9D\uFF84\uFF9E\uFF73;\uFF9B\uFF72\uFF84\uFF9E\u0031;;;",
-                        null, null, contentValuesForShiftJis,
+                        null, null, mContentValuesForSJis,
                         new TypeSet("X-IRMC-N"), null)
                 .addNodeWithOrder("ADR",
                         ";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
@@ -859,15 +845,16 @@
                                 "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
                                 "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
                                 "\u0036\u968E", "", "", "", "150-8512", ""),
-                        null, contentValuesForQPAndSJ, new TypeSet("HOME"), null)
+                        null, mContentValuesForQPAndSJis, new TypeSet("HOME"), null)
                 .addNodeWithOrder("NOTE", "\u30E1\u30E2", null, null,
-                        contentValuesForQPAndSJ, null, null);
+                        mContentValuesForQPAndSJis, null, null);
         verifier.verify(R.raw.v21_japanese_2, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
     }
 
     public void testV21Japanese2_Type_Generic_Utf8() throws IOException, VCardException {
-        ImportVerifierElem verifier = new ImportVerifierElem();
-        verifier.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4")
                 .put(StructuredName.GIVEN_NAME, "\u30ED\u30A4\u30C9\u0031")
                 .put(StructuredName.DISPLAY_NAME,
@@ -877,7 +864,7 @@
                 .put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF71\uFF9D\uFF84\uFF9E\uFF73")
                 .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF9B\uFF72\uFF84\uFF9E\u0031");
 
-        verifier.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
+        elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.POSTCODE, "150-8512")
                 .put(StructuredPostal.NEIGHBORHOOD,
                         "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
@@ -890,23 +877,21 @@
                         "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
                         "\u0036\u968E 150-8512")
                 .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
-        verifier.addExpected(Note.CONTENT_ITEM_TYPE)
+        elem.addExpected(Note.CONTENT_ITEM_TYPE)
                 .put(Note.NOTE, "\u30E1\u30E2");
         verifier.verify(R.raw.v21_japanese_2, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
     public void testV21MultipleEntryCase_Parse() throws IOException, VCardException {
-        ContentValues contentValuesForShiftJis = new ContentValues();
-        contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
         PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
         verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
-                        null, contentValuesForShiftJis, null, null)
+                        null, mContentValuesForSJis, null, null)
                 .addNodeWithOrder("SOUND",
                         "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
-                        null, null, contentValuesForShiftJis,
+                        null, null, mContentValuesForSJis,
                         new TypeSet("X-IRMC-N"), null)
                 .addNodeWithOrder("TEL", "9", new TypeSet("X-NEC-SECRET"))
                 .addNodeWithOrder("TEL", "10", new TypeSet("X-NEC-HOTEL"))
@@ -917,10 +902,10 @@
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
-                        null, contentValuesForShiftJis, null, null)
+                        null, mContentValuesForSJis, null, null)
                 .addNodeWithOrder("SOUND",
                         "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
-                        null, null, contentValuesForShiftJis,
+                        null, null, mContentValuesForSJis,
                         new TypeSet("X-IRMC-N"), null)
                 .addNodeWithOrder("TEL", "13", new TypeSet("MODEM"))
                 .addNodeWithOrder("TEL", "14", new TypeSet("PAGER"))
@@ -931,10 +916,10 @@
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
-                        null, contentValuesForShiftJis, null, null)
+                        null, mContentValuesForSJis, null, null)
                 .addNodeWithOrder("SOUND",
                         "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
-                        null, null, contentValuesForShiftJis,
+                        null, null, mContentValuesForSJis,
                         new TypeSet("X-IRMC-N"), null)
                 .addNodeWithOrder("TEL", "17", new TypeSet("X-NEC-BOY"))
                 .addNodeWithOrder("TEL", "18", new TypeSet("X-NEC-FRIEND"))
@@ -1013,4 +998,28 @@
                 .put(Phone.NUMBER, "20");
         verifier.verify(R.raw.v21_multiple_entry, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
     }
+
+    public void testPagerV30_Parse() throws IOException, VCardException {
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
+                .addNodeWithOrder("VERSION", "3.0")
+                .addNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
+                .addNodeWithOrder("TEL", "6101231234@pagersample.com",
+                        new TypeSet("WORK", "MSG", "PAGER"));
+        verifier.verify(R.raw.v30_comma_separated, VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8);
+    }
+
+    public void testPagerV30() throws IOException, VCardException {
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "F")
+                .put(StructuredName.MIDDLE_NAME, "M")
+                .put(StructuredName.GIVEN_NAME, "G")
+                .put(StructuredName.DISPLAY_NAME, "G M F");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_PAGER)
+                .put(Phone.NUMBER, "6101231234@pagersample.com");
+        verifier.verify(R.raw.v30_comma_separated, VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8);
+    }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java
new file mode 100644
index 0000000..4b65008
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.vcard;
+
+import android.content.ContentValues;
+import android.pim.vcard.VCardConfig;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+
+import com.android.unit_tests.vcard.PropertyNodesVerifierElem.TypeSet;
+
+import java.util.Arrays;
+
+public class VCardJapanizationTests extends VCardTestsBase {
+    private void testNameUtf8Common(int vcardType) {
+        ExportTestResolver resolver = new ExportTestResolver();
+        resolver.buildContactEntry().buildData(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
+                .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
+                .put(StructuredName.MIDDLE_NAME, "B")
+                .put(StructuredName.PREFIX, "Dr.")
+                .put(StructuredName.SUFFIX, "Ph.D");
+
+        VCardVerifier verifier = new VCardVerifier(resolver, vcardType);
+        ContentValues contentValues =
+            (VCardConfig.isV30(vcardType) ? null : mContentValuesForQPAndUtf8);
+        verifier.addPropertyNodesVerifierElem()
+                .addNodeWithoutOrder("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
+                        contentValues)
+                .addNodeWithoutOrder("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
+                        Arrays.asList(
+                                "\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
+                                null, contentValues, null, null);
+        verifier.verify();
+    }
+
+    public void testNameUtf8V21() {
+        testNameUtf8Common(VCardConfig.VCARD_TYPE_V21_JAPANESE_UTF8);
+    }
+
+    public void testNameUtf8V30() {
+        testNameUtf8Common(VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8);
+    }
+
+    public void testNameShiftJis() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        resolver.buildContactEntry().buildData(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
+                .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
+                .put(StructuredName.MIDDLE_NAME, "B")
+                .put(StructuredName.PREFIX, "Dr.")
+                .put(StructuredName.SUFFIX, "Ph.D");
+
+        VCardVerifier verifier = new VCardVerifier(resolver,
+                VCardConfig.VCARD_TYPE_V30_JAPANESE_SJIS);
+        verifier.addPropertyNodesVerifierElem()
+                .addNodeWithoutOrder("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
+                        mContentValuesForSJis)
+                .addNodeWithoutOrder("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
+                        Arrays.asList(
+                                "\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
+                                null, mContentValuesForSJis, null, null);
+        verifier.verify();
+    }
+
+    /**
+     * DoCoMo phones require all name elements should be in "family name" field.
+     */
+    public void testNameDoCoMo() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        resolver.buildContactEntry().buildData(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
+                .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
+                .put(StructuredName.MIDDLE_NAME, "B")
+                .put(StructuredName.PREFIX, "Dr.")
+                .put(StructuredName.SUFFIX, "Ph.D");
+
+        VCardVerifier verifier = new VCardVerifier(resolver,
+                VCardConfig.VCARD_TYPE_DOCOMO);
+        final String fullName = "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D";
+        verifier.addPropertyNodesVerifierElem()
+                .addNodeWithoutOrder("N", fullName + ";;;;",
+                        Arrays.asList(fullName, "", "", "", ""),
+                        null, mContentValuesForSJis, null, null)
+                .addNodeWithoutOrder("FN", fullName, mContentValuesForSJis)
+                .addNodeWithoutOrder("SOUND", ";;;;", new TypeSet("X-IRMC-N"))
+                .addNodeWithoutOrder("TEL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("EMAIL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("ADR", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("X-CLASS", "PUBLIC")
+                .addNodeWithoutOrder("X-REDUCTION", "")
+                .addNodeWithoutOrder("X-NO", "")
+                .addNodeWithoutOrder("X-DCM-HMN-MODE", "");
+        verifier.verify();
+    }
+}
\ No newline at end of file
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
index 9ec6e05..bd4d13a 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
@@ -66,7 +66,6 @@
 import android.test.mock.MockContext;
 import android.test.mock.MockCursor;
 import android.text.TextUtils;
-import android.util.Log;
 
 import junit.framework.TestCase;
 
@@ -185,6 +184,35 @@
     public static final int V21 = VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8;
     public static final int V30 = VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8;
 
+    // Do not modify these during tests.
+    protected final ContentValues mContentValuesForQP;
+    protected final ContentValues mContentValuesForSJis;
+    protected final ContentValues mContentValuesForUtf8;
+    protected final ContentValues mContentValuesForQPAndSJis;
+    protected final ContentValues mContentValuesForQPAndUtf8;
+    protected final ContentValues mContentValuesForBase64V21;
+    protected final ContentValues mContentValuesForBase64V30;
+
+    public VCardTestsBase() {
+        super();
+        mContentValuesForQP = new ContentValues();
+        mContentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+        mContentValuesForSJis = new ContentValues();
+        mContentValuesForSJis.put("CHARSET", "SHIFT_JIS");
+        mContentValuesForUtf8 = new ContentValues();
+        mContentValuesForUtf8.put("CHARSET", "UTF-8");
+        mContentValuesForQPAndSJis = new ContentValues();
+        mContentValuesForQPAndSJis.put("ENCODING", "QUOTED-PRINTABLE");
+        mContentValuesForQPAndSJis.put("CHARSET", "SHIFT_JIS");
+        mContentValuesForQPAndUtf8 = new ContentValues();
+        mContentValuesForQPAndUtf8.put("ENCODING", "QUOTED-PRINTABLE");
+        mContentValuesForQPAndUtf8.put("CHARSET", "UTF-8");
+        mContentValuesForBase64V21 = new ContentValues();
+        mContentValuesForBase64V21.put("ENCODING", "BASE64");
+        mContentValuesForBase64V30 = new ContentValues();
+        mContentValuesForBase64V30.put("ENCODING", "b");
+    }
+
     public class ImportTestResolver extends MockContentResolver {
         ImportTestProvider mProvider = new ImportTestProvider();
         @Override
@@ -834,7 +862,9 @@
 
             InputStream is = null;
             try {
-                is = new ByteArrayInputStream(vcard.getBytes("UTF-8"));
+                String charset =
+                    (VCardConfig.usesShiftJis(mVCardType) ? "SHIFT_JIS" : "UTF-8");
+                is = new ByteArrayInputStream(vcard.getBytes(charset));
                 testCase.assertEquals(true, parser.parse(is, null, builder));
             } catch (IOException e) {
                 testCase.fail("Unexpected IOException: " + e.getMessage());