Merge "Dedupe birthdays from raw contacts." into jb-mr1-dev
diff --git a/res/drawable-hdpi/tab_selected_focused_holo.9.png b/res/drawable-hdpi/tab_selected_focused_holo.9.png
deleted file mode 100644
index feaaa2d..0000000
--- a/res/drawable-hdpi/tab_selected_focused_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_holo.9.png b/res/drawable-hdpi/tab_selected_holo.9.png
deleted file mode 100644
index b939b5d..0000000
--- a/res/drawable-hdpi/tab_selected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/res/drawable-hdpi/tab_selected_pressed_holo.9.png
deleted file mode 100644
index ccb7342..0000000
--- a/res/drawable-hdpi/tab_selected_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_focused_holo.9.png b/res/drawable-hdpi/tab_unselected_focused_holo.9.png
deleted file mode 100644
index 4f59d32..0000000
--- a/res/drawable-hdpi/tab_unselected_focused_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_holo.9.png b/res/drawable-hdpi/tab_unselected_holo.9.png
deleted file mode 100644
index de9f4f2..0000000
--- a/res/drawable-hdpi/tab_unselected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
deleted file mode 100644
index 8e706b0..0000000
--- a/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_focused_holo.9.png b/res/drawable-mdpi/tab_selected_focused_holo.9.png
deleted file mode 100644
index ffe76c7..0000000
--- a/res/drawable-mdpi/tab_selected_focused_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_holo.9.png b/res/drawable-mdpi/tab_selected_holo.9.png
deleted file mode 100644
index 6ccbd47..0000000
--- a/res/drawable-mdpi/tab_selected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/res/drawable-mdpi/tab_selected_pressed_holo.9.png
deleted file mode 100644
index 834b1f5..0000000
--- a/res/drawable-mdpi/tab_selected_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_focused_holo.9.png b/res/drawable-mdpi/tab_unselected_focused_holo.9.png
deleted file mode 100644
index 9cf9398..0000000
--- a/res/drawable-mdpi/tab_unselected_focused_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_holo.9.png b/res/drawable-mdpi/tab_unselected_holo.9.png
deleted file mode 100644
index 5834c1f..0000000
--- a/res/drawable-mdpi/tab_unselected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
deleted file mode 100644
index b205bc7..0000000
--- a/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_selected_focused_holo.9.png b/res/drawable-xhdpi/tab_selected_focused_holo.9.png
deleted file mode 100644
index 8bb6ec5..0000000
--- a/res/drawable-xhdpi/tab_selected_focused_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_selected_holo.9.png b/res/drawable-xhdpi/tab_selected_holo.9.png
deleted file mode 100644
index 81d5b34..0000000
--- a/res/drawable-xhdpi/tab_selected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_selected_pressed_holo.9.png b/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
deleted file mode 100644
index 9ae1441..0000000
--- a/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_unselected_focused_holo.9.png b/res/drawable-xhdpi/tab_unselected_focused_holo.9.png
deleted file mode 100644
index 5973936..0000000
--- a/res/drawable-xhdpi/tab_unselected_focused_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_unselected_holo.9.png b/res/drawable-xhdpi/tab_unselected_holo.9.png
deleted file mode 100644
index 1590ba8..0000000
--- a/res/drawable-xhdpi/tab_unselected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png b/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
deleted file mode 100644
index b781355..0000000
--- a/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/action_bar_tab.xml b/res/drawable/action_bar_tab.xml
index 7676549..0af5e08 100644
--- a/res/drawable/action_bar_tab.xml
+++ b/res/drawable/action_bar_tab.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2011 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.
@@ -15,30 +16,11 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:state_pressed="true"
-        android:state_selected="true"
-        android:drawable="@drawable/tab_selected_pressed_holo"/>
-    <item
-        android:state_focused="true"
-        android:state_selected="true"
-        android:drawable="@drawable/tab_selected_focused_holo"/>
-    <item
-        android:state_focused="true"
-        android:state_selected="false"
-        android:drawable="@drawable/tab_unselected_focused_holo"/>
-    <item
-        android:state_pressed="true"
-        android:state_selected="false"
-        android:drawable="@drawable/tab_unselected_pressed_holo"/>
-    <item
-        android:state_focused="false"
-        android:state_selected="true"
-        android:state_pressed="false"
-        android:drawable="@drawable/tab_selected_holo"/>
-    <item
-        android:state_focused="false"
-        android:state_pressed="false"
-        android:state_selected="false"
-        android:drawable="@drawable/tab_unselected_holo"/>
+
+    <item android:drawable="@drawable/tab_selected_pressed" android:state_pressed="true" android:state_selected="true"/>
+    <item android:drawable="@drawable/tab_selected_focused" android:state_focused="true" android:state_selected="true"/>
+    <item android:drawable="@drawable/tab_selected" android:state_selected="true"/>
+    <item android:drawable="@drawable/tab_unselected_pressed" android:state_pressed="true"/>
+    <item android:drawable="@drawable/tab_unselected_focused" android:state_focused="true"/>
+
 </selector>
\ No newline at end of file
diff --git a/res/drawable/tab_selected.xml b/res/drawable/tab_selected.xml
new file mode 100644
index 0000000..5d57ea2
--- /dev/null
+++ b/res/drawable/tab_selected.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#ffffffff" />
+        </shape>
+    </item>
+    <item android:bottom="6dp">
+        <shape android:shape="rectangle" >
+            <solid android:color="@color/people_app_theme_color" />
+        </shape>
+    </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/tab_selected_focused.xml b/res/drawable/tab_selected_focused.xml
new file mode 100644
index 0000000..7a44ef5
--- /dev/null
+++ b/res/drawable/tab_selected_focused.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#ffffffff" />
+        </shape>
+    </item>
+    <item android:bottom="6dp">
+        <shape android:shape="rectangle" >
+            <solid android:color="@color/people_app_theme_color" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#27ffffff" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#00000000" />
+
+            <stroke
+                android:width="2dp"
+                android:color="#27ffffff" />
+        </shape>
+    </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/tab_selected_pressed.xml b/res/drawable/tab_selected_pressed.xml
new file mode 100644
index 0000000..e3d9d26
--- /dev/null
+++ b/res/drawable/tab_selected_pressed.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#ffffffff" />
+        </shape>
+    </item>
+    <item android:bottom="6dp">
+        <shape android:shape="rectangle" >
+            <solid android:color="@color/people_app_theme_color" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#4dffffff" />
+        </shape>
+    </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/tab_unselected_focused.xml b/res/drawable/tab_unselected_focused.xml
new file mode 100644
index 0000000..f34d99b
--- /dev/null
+++ b/res/drawable/tab_unselected_focused.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#27ffffff" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#00000000" />
+
+            <stroke
+                android:width="2dp"
+                android:color="#27ffffff" />
+        </shape>
+    </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/tab_unselected_pressed.xml b/res/drawable/tab_unselected_pressed.xml
new file mode 100644
index 0000000..784acc1
--- /dev/null
+++ b/res/drawable/tab_unselected_pressed.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item>
+        <shape android:shape="rectangle" >
+            <solid android:color="#4dffffff" />
+        </shape>
+    </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 74e6a0a..5870b48 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -412,9 +412,9 @@
     <string name="take_photo" msgid="7496128293167402354">"Tirar fotografia"</string>
     <string name="take_new_photo" msgid="7341354729436576304">"Tirar nova fotografia"</string>
     <string name="pick_photo" msgid="3746334626214970837">"Escolher fotografia da Galeria"</string>
-    <string name="pick_new_photo" msgid="7962368009197147617">"Seleccionar nova fotografia da Galeria"</string>
-    <string name="locale_change_in_progress" msgid="7583992153091537467">"A lista de contactos está a ser actualizada para reflectir a alteração do idioma."</string>
-    <string name="upgrade_in_progress" msgid="474511436863451061">"A lista de contactos está a ser actualizada."</string>
+    <string name="pick_new_photo" msgid="7962368009197147617">"Selecionar nova fotografia da Galeria"</string>
+    <string name="locale_change_in_progress" msgid="7583992153091537467">"A lista de contactos está a ser atualizada para reflectir a alteração do idioma."</string>
+    <string name="upgrade_in_progress" msgid="474511436863451061">"A lista de contactos está a ser atualizada."</string>
     <string name="upgrade_out_of_memory" msgid="1209994418877625940">"Os contactos estão em processo de atualização. "\n\n"O processo de atualização requer aproximadamente <xliff:g id="SIZE_IN_MEGABYTES">%s</xliff:g> MB de armazenamento interno."\n\n"Escolha uma das seguintes opções:"</string>
     <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Desinstalar algumas aplicações"</string>
     <string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Repetir actualização"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index c9427ae..3e5d304 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -510,7 +510,7 @@
     <string name="voicemail_fetching_timout" msgid="6691792377574905201">"ไม่สามารถดึงข้อความเสียง"</string>
     <string name="call_log_new_header" msgid="846546437517724715">"ใหม่"</string>
     <string name="call_log_old_header" msgid="6262205894314263629">"เก่ากว่า"</string>
-    <string name="call_log_voicemail_header" msgid="4484032064803446806">"สายโทรที่มีข้อความเสียง"</string>
+    <string name="call_log_voicemail_header" msgid="4484032064803446806">"สายที่ฝากข้อความเสียง"</string>
     <string name="call_log_incoming_header" msgid="297542827180501480">"สายเรียกเข้า"</string>
     <string name="call_log_outgoing_header" msgid="9017138725495067284">"สายโทรออก"</string>
     <string name="call_log_missed_header" msgid="2168865291934970151">"สายที่ไม่ได้รับ"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 567f985..7d93ad6 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -510,7 +510,7 @@
     <string name="voicemail_fetching_timout" msgid="6691792377574905201">"无法抓取语音邮件。"</string>
     <string name="call_log_new_header" msgid="846546437517724715">"新记录"</string>
     <string name="call_log_old_header" msgid="6262205894314263629">"旧记录"</string>
-    <string name="call_log_voicemail_header" msgid="4484032064803446806">"通过语音信箱接听的电话"</string>
+    <string name="call_log_voicemail_header" msgid="4484032064803446806">"通过语音信箱接到的电话"</string>
     <string name="call_log_incoming_header" msgid="297542827180501480">"来电"</string>
     <string name="call_log_outgoing_header" msgid="9017138725495067284">"外拨电话"</string>
     <string name="call_log_missed_header" msgid="2168865291934970151">"未接来电"</string>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index dd94097..2110a8b 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -55,9 +55,6 @@
     specific to some vendor (like DoCoMo), specify this type (e.g. "docomo") -->
     <string name="config_export_vcard_type" translatable="false">default</string>
 
-    <!-- Directory in which exported VCard file is stored -->
-    <string name="config_export_dir" translatable="false">/mnt/sdcard</string>
-
     <!-- Prefix of exported VCard file -->
     <string name="config_export_file_prefix" translatable="false"></string>
 
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index f82d91a..3dfaf8d 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -42,7 +42,6 @@
 import android.provider.ContactsContract.Directory;
 import android.provider.ContactsContract.DisplayNameSources;
 import android.provider.ContactsContract.StatusUpdates;
-import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -574,9 +573,7 @@
                 } else if (dataItem instanceof PhoneDataItem && hasData) {
                     PhoneDataItem phone = (PhoneDataItem) dataItem;
                     // Build phone entries
-                    String phoneNumberE164 = phone.getNormalizedNumber();
-                    entry.data = PhoneNumberUtils.formatNumber(
-                            entry.data, phoneNumberE164, mDefaultCountryIso);
+                    entry.data = phone.getFormattedPhoneNumber();
                     final Intent phoneIntent = mHasPhone ?
                             ContactsUtils.getCallIntent(entry.data) : null;
                     final Intent smsIntent = mHasSms ? new Intent(Intent.ACTION_SENDTO,
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index 6a69744..37fabb0 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -187,7 +187,7 @@
             Uri lookupUri = args.getParcelable(LOADER_ARG_CONTACT_URI);
             return new ContactLoader(mContext, lookupUri, true /* loadGroupMetaData */,
                     true /* loadStreamItems */, true /* load invitable account types */,
-                    true /* postViewNotification */);
+                    true /* postViewNotification */, true /* computeFormattedPhoneNumber */);
         }
 
         @Override
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 780279e..5ee6ff9 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -675,6 +675,12 @@
     }
 
     private void bindEditors() {
+        // bindEditors() can only bind views if there is data in mState, so immediately return
+        // if mState is null
+        if (mState == null) {
+            return;
+        }
+
         // Sort the editors
         Collections.sort(mState, mComparator);
 
diff --git a/src/com/android/contacts/model/ContactLoader.java b/src/com/android/contacts/model/ContactLoader.java
index 28000a6..f9f630d 100644
--- a/src/com/android/contacts/model/ContactLoader.java
+++ b/src/com/android/contacts/model/ContactLoader.java
@@ -41,10 +41,12 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 
+import com.android.contacts.ContactsUtils;
 import com.android.contacts.GroupMetaData;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountTypeWithDataSet;
 import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.model.dataitem.PhoneDataItem;
 import com.android.contacts.model.dataitem.PhotoDataItem;
 import com.android.contacts.util.ContactLoaderUtils;
 import com.android.contacts.util.DataStatus;
@@ -61,6 +63,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -81,17 +84,18 @@
     private boolean mLoadStreamItems;
     private boolean mLoadInvitableAccountTypes;
     private boolean mPostViewNotification;
+    private boolean mComputeFormattedPhoneNumber;
     private Contact mContact;
     private ForceLoadContentObserver mObserver;
     private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
 
     public ContactLoader(Context context, Uri lookupUri, boolean postViewNotification) {
-        this(context, lookupUri, false, false, false, postViewNotification);
+        this(context, lookupUri, false, false, false, postViewNotification, false);
     }
 
     public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
             boolean loadStreamItems, boolean loadInvitableAccountTypes,
-            boolean postViewNotification) {
+            boolean postViewNotification, boolean computeFormattedPhoneNumber) {
         super(context);
         mLookupUri = lookupUri;
         mRequestedUri = lookupUri;
@@ -99,6 +103,7 @@
         mLoadStreamItems = loadStreamItems;
         mLoadInvitableAccountTypes = loadInvitableAccountTypes;
         mPostViewNotification = postViewNotification;
+        mComputeFormattedPhoneNumber = computeFormattedPhoneNumber;
     }
 
     /**
@@ -328,6 +333,9 @@
                 if (mLoadStreamItems && result.getStreamItems() == null) {
                     loadStreamItems(result);
                 }
+                if (mComputeFormattedPhoneNumber) {
+                    computeFormattedPhoneNumbers(result);
+                }
                 if (!resultIsCached) loadPhotoBinaryData(result);
 
                 // Note ME profile should never have "Add connection"
@@ -379,7 +387,7 @@
                 }
                 if (!cursor.isNull(ContactQuery.DATA_ID)) {
                     ContentValues data = loadDataValues(cursor);
-                    rawContact.addDataItemValues(data);
+                    final DataItem item = rawContact.addDataItemValues(data);
 
                     if (!cursor.isNull(ContactQuery.PRESENCE)
                             || !cursor.isNull(ContactQuery.STATUS)) {
@@ -790,6 +798,29 @@
                 .build());
     }
 
+    /**
+     * Iterates over all data items that represent phone numbers are tries to calculate a formatted
+     * number. This function can safely be called several times as no unformatted data is
+     * overwritten
+     */
+    private void computeFormattedPhoneNumbers(Contact contactData) {
+        final String countryIso = ContactsUtils.getCurrentCountryIso(getContext());
+        final ImmutableList<RawContact> rawContacts = contactData.getRawContacts();
+        final int rawContactCount = rawContacts.size();
+        for (int rawContactIndex = 0; rawContactIndex < rawContactCount; rawContactIndex++) {
+            final RawContact rawContact = rawContacts.get(rawContactIndex);
+            final List<DataItem> dataItems = rawContact.getDataItems();
+            final int dataCount = dataItems.size();
+            for (int dataIndex = 0; dataIndex < dataCount; dataIndex++) {
+                final DataItem dataItem = dataItems.get(dataIndex);
+                if (dataItem instanceof PhoneDataItem) {
+                    final PhoneDataItem phoneDataItem = (PhoneDataItem) dataItem;
+                    phoneDataItem.computeFormattedPhoneNumber(countryIso);
+                }
+            }
+        }
+    }
+
     @Override
     public void deliverResult(Contact result) {
         unregisterObserver();
@@ -877,12 +908,13 @@
     public void upgradeToFullContact() {
         // Everything requested already? Nothing to do, so let's bail out
         if (mLoadGroupMetaData && mLoadInvitableAccountTypes && mLoadStreamItems
-                && mPostViewNotification) return;
+                && mPostViewNotification && mComputeFormattedPhoneNumber) return;
 
         mLoadGroupMetaData = true;
         mLoadInvitableAccountTypes = true;
         mLoadStreamItems = true;
         mPostViewNotification = true;
+        mComputeFormattedPhoneNumber = true;
 
         // Cache the current result, so that we only load the "missing" parts of the contact.
         cacheResult();
diff --git a/src/com/android/contacts/model/RawContact.java b/src/com/android/contacts/model/RawContact.java
index d884198..6d4a881 100644
--- a/src/com/android/contacts/model/RawContact.java
+++ b/src/com/android/contacts/model/RawContact.java
@@ -228,12 +228,18 @@
         setAccount(null, null, null);
     }
 
-    public void addDataItemValues(ContentValues values) {
-        addNamedDataItemValues(Data.CONTENT_URI, values);
+    /**
+     * Creates and inserts a DataItem object that wraps the content values, and returns it.
+     */
+    public DataItem addDataItemValues(ContentValues values) {
+        final NamedDataItem namedItem = addNamedDataItemValues(Data.CONTENT_URI, values);
+        return namedItem.dataItem;
     }
 
-    public void addNamedDataItemValues(Uri uri, ContentValues values) {
-        mDataItems.add(new NamedDataItem(uri, DataItem.createFrom(this, values)));
+    public NamedDataItem addNamedDataItemValues(Uri uri, ContentValues values) {
+        final NamedDataItem namedItem = new NamedDataItem(uri, DataItem.createFrom(this, values));
+        mDataItems.add(namedItem);
+        return namedItem;
     }
 
     public List<DataItem> getDataItems() {
diff --git a/src/com/android/contacts/model/dataitem/PhoneDataItem.java b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
index 94a0054..61d62c1 100644
--- a/src/com/android/contacts/model/dataitem/PhoneDataItem.java
+++ b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
@@ -19,6 +19,7 @@
 import android.content.ContentValues;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.PhoneNumberUtils;
 
 import com.android.contacts.model.RawContact;
 
@@ -28,6 +29,8 @@
  */
 public class PhoneDataItem extends DataItem {
 
+    public static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber";
+
     /* package */ PhoneDataItem(RawContact rawContact, ContentValues values) {
         super(rawContact, values);
     }
@@ -43,6 +46,10 @@
         return getContentValues().getAsString(Phone.NORMALIZED_NUMBER);
     }
 
+    public String getFormattedPhoneNumber() {
+        return getContentValues().getAsString(KEY_FORMATTED_PHONE_NUMBER);
+    }
+
     /**
      * Values are Phone.TYPE_*
      */
@@ -54,4 +61,13 @@
         return getContentValues().getAsString(Phone.LABEL);
     }
 
+    public void computeFormattedPhoneNumber(String defaultCountryIso) {
+        final String phoneNumber = getNumber();
+        if (phoneNumber != null) {
+            final String formattedPhoneNumber = PhoneNumberUtils.formatNumber(phoneNumber,
+                    getNormalizedNumber(), defaultCountryIso);
+            getContentValues().put(KEY_FORMATTED_PHONE_NUMBER, formattedPhoneNumber);
+        }
+    }
+
 }
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 03517d4..259f38d 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -114,7 +114,7 @@
             return;
         }
         final ContactLoader contactLoader = new ContactLoader(context, contactUri, false, true,
-                false, true);
+                false, true, false);
         contactLoader.registerListener(0,
                 new ContactLoader.OnLoadCompleteListener<Contact>() {
                     @Override
diff --git a/src/com/android/contacts/vcard/ExportVCardActivity.java b/src/com/android/contacts/vcard/ExportVCardActivity.java
index ac0850f..6bed577 100644
--- a/src/com/android/contacts/vcard/ExportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ExportVCardActivity.java
@@ -25,6 +25,7 @@
 import android.content.ServiceConnection;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -148,7 +149,14 @@
         super.onCreate(bundle);
 
         // Check directory is available.
-        final File targetDirectory = new File(getString(R.string.config_export_dir));
+        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            Log.w(LOG_TAG, "External storage is in state " + Environment.getExternalStorageState() +
+                    ". Cancelling export");
+            showDialog(R.id.dialog_sdcard_not_found);
+            return;
+        }
+
+        final File targetDirectory = Environment.getExternalStorageDirectory();
         if (!(targetDirectory.exists() &&
                 targetDirectory.isDirectory() &&
                 targetDirectory.canRead()) &&
diff --git a/src/com/android/contacts/vcard/VCardService.java b/src/com/android/contacts/vcard/VCardService.java
index 4ef1bcb..74ce69c 100644
--- a/src/com/android/contacts/vcard/VCardService.java
+++ b/src/com/android/contacts/vcard/VCardService.java
@@ -22,6 +22,7 @@
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Environment;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
@@ -117,7 +118,7 @@
     // If true, VCardExporter is able to emits files longer than 8.3 format.
     private static final boolean ALLOW_LONG_FILE_NAME = false;
 
-    private String mTargetDirectory;
+    private File mTargetDirectory;
     private String mFileNamePrefix;
     private String mFileNameSuffix;
     private int mFileIndexMinimum;
@@ -146,7 +147,7 @@
     }
 
     private void initExporterParams() {
-        mTargetDirectory = getString(R.string.config_export_dir);
+        mTargetDirectory = Environment.getExternalStorageDirectory();
         mFileNamePrefix = getString(R.string.config_export_file_prefix);
         mFileNameSuffix = getString(R.string.config_export_file_suffix);
         mFileNameExtension = getString(R.string.config_export_file_extension);
@@ -453,7 +454,7 @@
      * @return destination path for a vCard file to be exported. null on error and mErrorReason
      * is correctly set.
      */
-    private String getAppropriateDestination(final String destDirectory) {
+    private String getAppropriateDestination(final File destDirectory) {
         /*
          * Here, file names have 5 parts: directory, prefix, index, suffix, and extension.
          * e.g. "/mnt/sdcard/prfx00001sfx.vcf" -> "/mnt/sdcard", "prfx", "00001", "sfx", and ".vcf"
@@ -498,28 +499,30 @@
 
         for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
             boolean numberIsAvailable = true;
-            String body = null;
+            final String body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
+            // Make sure that none of the extensions of mExtensionsToConsider matches. If this
+            // number is free, we'll go ahead with mFileNameExtension (which is included in
+            // mExtensionsToConsider)
             for (String possibleExtension : mExtensionsToConsider) {
-                body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
-                final String path =
-                        String.format("%s/%s.%s", destDirectory, body, possibleExtension);
+                final File file = new File(destDirectory, body + "." + possibleExtension);
+                final String path = file.getAbsolutePath();
                 synchronized (this) {
+                    // Is this being exported right now? Skip this number
                     if (mReservedDestination.contains(path)) {
                         if (DEBUG) {
-                            Log.d(LOG_TAG, String.format("The path %s is reserved.", path));
+                            Log.d(LOG_TAG, String.format("%s is already being exported.", path));
                         }
                         numberIsAvailable = false;
                         break;
                     }
                 }
-                final File file = new File(path);
                 if (file.exists()) {
                     numberIsAvailable = false;
                     break;
                 }
             }
             if (numberIsAvailable) {
-                return String.format("%s/%s.%s", destDirectory, body, mFileNameExtension);
+                return new File(destDirectory, body + "." + mFileNameExtension).getAbsolutePath();
             }
         }