Merge "Make quick contact badge accessible."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a1829d1..f4dcdf6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
diff --git a/res/drawable-hdpi/btn_dial_pressed.png b/res/drawable-hdpi/btn_dial_pressed.png
deleted file mode 100644
index 9c73cca..0000000
--- a/res/drawable-hdpi/btn_dial_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_selected.9.png b/res/drawable-hdpi/btn_dial_selected.9.png
deleted file mode 100644
index 6372fa0..0000000
--- a/res/drawable-hdpi/btn_dial_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_selector_disabled_holo_dark.9.png b/res/drawable-hdpi/list_selector_disabled_holo_dark.9.png
new file mode 100644
index 0000000..f6fd30d
--- /dev/null
+++ b/res/drawable-hdpi/list_selector_disabled_holo_dark.9.png
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_pressed.png b/res/drawable-mdpi/btn_dial_pressed.png
deleted file mode 100644
index 2440553..0000000
--- a/res/drawable-mdpi/btn_dial_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_selected.9.png b/res/drawable-mdpi/btn_dial_selected.9.png
deleted file mode 100644
index f9258a1..0000000
--- a/res/drawable-mdpi/btn_dial_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/list_selector_disabled_holo_dark.9.png b/res/drawable-mdpi/list_selector_disabled_holo_dark.9.png
new file mode 100644
index 0000000..92da2f0
--- /dev/null
+++ b/res/drawable-mdpi/list_selector_disabled_holo_dark.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_pressed.png b/res/drawable-xhdpi/btn_dial_pressed.png
deleted file mode 100644
index 27c95b7..0000000
--- a/res/drawable-xhdpi/btn_dial_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_selected.9.png b/res/drawable-xhdpi/btn_dial_selected.9.png
deleted file mode 100644
index 1e2fe56..0000000
--- a/res/drawable-xhdpi/btn_dial_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/list_selector_disabled_holo_dark.9.png b/res/drawable-xhdpi/list_selector_disabled_holo_dark.9.png
new file mode 100644
index 0000000..88726b6
--- /dev/null
+++ b/res/drawable-xhdpi/list_selector_disabled_holo_dark.9.png
Binary files differ
diff --git a/res/drawable/btn_call.xml b/res/drawable/btn_call.xml
index 51c2b7d..73ff87b 100644
--- a/res/drawable/btn_call.xml
+++ b/res/drawable/btn_call.xml
@@ -14,12 +14,20 @@
      limitations under the License.
 -->
 
-<!-- Background resource for call button in the various dialpads -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-        android:drawable="@drawable/btn_call_pressed" />
-    <item android:state_focused="true"
-        android:drawable="@drawable/btn_dial_selected" />
-    <item
-        android:drawable="@android:color/transparent" />
+<!-- Background resource for call button in the various dialpads.
+     Almost a copy from framework's item_background_holo_dark.xml, but has different pressed effect
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+    <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_dark" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/list_selector_disabled_holo_dark" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/btn_call_pressed" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/btn_call_pressed" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/list_focused_holo" />
+    <item                                                                                          android:drawable="@android:color/transparent" />
 </selector>
+
diff --git a/res/drawable/btn_dial.xml b/res/drawable/btn_dial.xml
deleted file mode 100644
index 2a577e0..0000000
--- a/res/drawable/btn_dial.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<!-- Background resource for digit buttons in the various dialpads
-	 used by the Contacts app (see dialpad.xml).
-     -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-        android:drawable="@drawable/btn_dial_pressed" />
-    <item android:state_focused="true"
-        android:drawable="@drawable/btn_dial_selected" />
-
-    <item
-        android:drawable="@android:color/transparent" />
-</selector>
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 936bca8..a890ddf 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -156,7 +156,7 @@
                     android:orientation="vertical"
                     android:gravity="center_vertical"
                     android:focusable="true"
-                    android:background="@drawable/btn_dial"
+                    android:background="?android:attr/selectableItemBackground"
                 >
 
                     <TextView android:id="@+id/call_and_sms_text"
@@ -191,7 +191,7 @@
                     android:gravity="center"
                     android:scaleType="centerInside"
                     android:focusable="true"
-                    android:background="@drawable/btn_dial"
+                    android:background="?android:attr/selectableItemBackground"
                 />
             </LinearLayout>
         </FrameLayout>
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 26689be..852b6f7 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -46,6 +46,8 @@
             android:layout_height="match_parent"
             android:text="@string/recentCalls_empty"
             android:gravity="center"
+            android:layout_marginTop="@dimen/empty_message_top_margin"
+            android:textColor="?android:attr/textColorSecondary"
             android:textAppearance="?android:attr/textAppearanceLarge"
         />
     </FrameLayout>
diff --git a/res/layout/contact_detail_fragment_carousel.xml b/res/layout/contact_detail_fragment_carousel.xml
index 4f65549..2572cc4 100644
--- a/res/layout/contact_detail_fragment_carousel.xml
+++ b/res/layout/contact_detail_fragment_carousel.xml
@@ -30,7 +30,9 @@
         android:id="@+id/about_fragment_container"
         android:layout_width="0dip"
         android:layout_height="match_parent"
-        android:layout_weight="1" />
+        android:layout_weight="1"
+        android:focusable="true"
+        android:focusableInTouchMode="true" />
 
     <!--
       Container for the "Updates" page fragment on the contact card for a contact
@@ -42,6 +44,8 @@
         android:layout_width="0dip"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:visibility="gone" />
+        android:visibility="gone"
+        android:focusable="true"
+        android:focusableInTouchMode="true" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/dialpad_additional_buttons.xml b/res/layout/dialpad_additional_buttons.xml
index f0e4a42..ae37fd5 100644
--- a/res/layout/dialpad_additional_buttons.xml
+++ b/res/layout/dialpad_additional_buttons.xml
@@ -33,7 +33,7 @@
         android:layout_height="match_parent"
         android:layout_gravity="center_vertical"
         android:state_enabled="false"
-        android:background="@drawable/btn_dial"
+        android:background="?android:attr/selectableItemBackground"
         android:contentDescription="@string/description_search_button"
         android:src="@drawable/ic_see_contacts_holo_dark"/>
 
@@ -57,7 +57,7 @@
         android:layout_height="match_parent"
         android:layout_gravity="center_vertical"
         android:state_enabled="false"
-        android:background="@drawable/btn_dial"
+        android:background="?android:attr/selectableItemBackground"
         android:contentDescription="@string/description_delete_button"
         android:src="@drawable/ic_dial_action_delete" />
 </LinearLayout>
diff --git a/res/layout/dialpad_fragment.xml b/res/layout/dialpad_fragment.xml
index b2784e2..96cf543 100644
--- a/res/layout/dialpad_fragment.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -30,30 +30,29 @@
         android:layout_height="0px"
         android:layout_weight="0.200"
         android:layout_marginTop="@dimen/dialpad_vertical_margin"
-        android:gravity="center" >
+        android:gravity="center"
+        android:background="@drawable/dialpad_background" >
 
-        <!-- Type of this EditText is set to NULL (to disable the IME keyboard)
-             in the java code.
-
-             Background drawable can be controlled programatically. -->
         <com.android.contacts.dialpad.DigitsEditText
             android:id="@+id/digits"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_alignParentLeft="true"
-            android:layout_toLeftOf="@+id/moreoverflow"
-            android:background="@drawable/dialpad_background"
             android:gravity="center"
             android:textAppearance="@style/DialtactsDigitsTextAppearance"
-            android:textColor="?android:attr/textColorPrimary" />
+            android:textColor="?android:attr/textColorPrimary"
+            android:nextFocusRight="@+id/overflow_menu"
+            android:background="@android:color/transparent" />
 
-        <ImageButton android:id="@+id/overflow_menu"
+        <ImageButton
+            android:id="@+id/overflow_menu"
             android:layout_width="48dip"
             android:layout_height="match_parent"
             android:layout_alignParentRight="true"
             android:src="@drawable/ic_menu_overflow"
             android:contentDescription="@*android:string/action_menu_overflow_description"
-            android:background="@android:color/transparent"/>
+            android:nextFocusLeft="@id/digits"
+            android:background="?android:attr/selectableItemBackground"/>
 
     </RelativeLayout>
 
diff --git a/res/layout/dialtacts_custom_action_bar.xml b/res/layout/dialtacts_custom_action_bar.xml
index 2be66f7..0709626 100644
--- a/res/layout/dialtacts_custom_action_bar.xml
+++ b/res/layout/dialtacts_custom_action_bar.xml
@@ -31,11 +31,12 @@
     <ImageButton
         android:id="@+id/search_option"
         android:layout_width="wrap_content"
-        android:paddingRight="8dip"
+        android:paddingLeft="4dip"
+        android:paddingRight="4dip"
         android:layout_height="match_parent"
         android:layout_alignParentRight="true"
         android:src="@drawable/ic_menu_overflow"
-        android:background="@android:color/transparent"
+        android:background="?android:attr/selectableItemBackground"
         android:visibility="gone" />
 
 </LinearLayout>
diff --git a/res/layout/favorites_star.xml b/res/layout/favorites_star.xml
index 5bdc091..2ac3039 100644
--- a/res/layout/favorites_star.xml
+++ b/res/layout/favorites_star.xml
@@ -30,4 +30,4 @@
         android:contentDescription="@string/description_star"
         android:visibility="invisible"
         android:button="@drawable/btn_star_holo_dark"/>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/res/layout/playback_layout.xml b/res/layout/playback_layout.xml
index c2fdb3e..711ebf8 100644
--- a/res/layout/playback_layout.xml
+++ b/res/layout/playback_layout.xml
@@ -24,7 +24,7 @@
                 android:id="@+id/playback_start_stop"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:background="@drawable/btn_dial"
+                android:background="?android:attr/selectableItemBackground"
                 android:src="@drawable/ic_hold_pause"
             />
         </LinearLayout>
@@ -38,7 +38,7 @@
                 android:id="@+id/playback_speakerphone"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:background="@drawable/btn_dial"
+                android:background="?android:attr/selectableItemBackground"
                 android:src="@drawable/ic_speakerphone_on"
             />
         </LinearLayout>
@@ -97,7 +97,7 @@
             android:src="@drawable/ic_minus"
             android:layout_width="64dip"
             android:layout_height="wrap_content"
-            android:background="@drawable/btn_dial"
+            android:background="?android:attr/selectableItemBackground"
             android:paddingBottom="19dip"
             android:paddingTop="29dip"
             android:layout_alignParentLeft="true"
@@ -108,7 +108,7 @@
             android:src="@drawable/ic_plus"
             android:layout_width="64dip"
             android:layout_height="wrap_content"
-            android:background="@drawable/btn_dial"
+            android:background="?android:attr/selectableItemBackground"
             android:paddingBottom="19dip"
             android:paddingTop="29dip"
             android:layout_alignParentRight="true"
diff --git a/res/mipmap-hdpi/ic_launcher_contacts.png b/res/mipmap-hdpi/ic_launcher_contacts.png
index 5ebe2e0..fa60a53 100644
--- a/res/mipmap-hdpi/ic_launcher_contacts.png
+++ b/res/mipmap-hdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-hdpi/ic_launcher_phone.png b/res/mipmap-hdpi/ic_launcher_phone.png
index e56c507..5a3dff1 100644
--- a/res/mipmap-hdpi/ic_launcher_phone.png
+++ b/res/mipmap-hdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_contacts.png b/res/mipmap-mdpi/ic_launcher_contacts.png
index c79ae14..b50d7dd 100644
--- a/res/mipmap-mdpi/ic_launcher_contacts.png
+++ b/res/mipmap-mdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_phone.png b/res/mipmap-mdpi/ic_launcher_phone.png
index 1f40fd0..9ea0d8c 100644
--- a/res/mipmap-mdpi/ic_launcher_phone.png
+++ b/res/mipmap-mdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_contacts.png b/res/mipmap-xhdpi/ic_launcher_contacts.png
index ca3aa63..4b7eaaa 100644
--- a/res/mipmap-xhdpi/ic_launcher_contacts.png
+++ b/res/mipmap-xhdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_phone.png b/res/mipmap-xhdpi/ic_launcher_phone.png
index e23a58c..e97836c 100644
--- a/res/mipmap-xhdpi/ic_launcher_phone.png
+++ b/res/mipmap-xhdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4317050..0b47d5a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -237,7 +237,7 @@
         <item name="android:layout_width">0dip</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:layout_weight">1</item>
-        <item name="android:background">@drawable/btn_dial</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
         <item name="android:soundEffectsEnabled">false</item>
     </style>
 
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 2df2e47..e465772 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -323,10 +323,26 @@
                 if (rawContactId == -1) {
                     throw new IllegalStateException("Could not determine RawContact ID after save");
                 }
-                final Uri rawContactUri = ContentUris.withAppendedId(
-                        isProfile ? Profile.CONTENT_RAW_CONTACTS_URI : RawContacts.CONTENT_URI,
-                                rawContactId);
-                lookupUri = RawContacts.getContactLookupUri(resolver, rawContactUri);
+                if (isProfile) {
+                    // Since the profile supports local raw contacts, which may have been completely
+                    // removed if all information was removed, we need to do a special query to
+                    // get the lookup URI for the profile contact (if it still exists).
+                    Cursor c = resolver.query(Profile.CONTENT_URI,
+                            new String[] {Contacts._ID, Contacts.LOOKUP_KEY},
+                            null, null, null);
+                    try {
+                        c.moveToFirst();
+                        final long contactId = c.getLong(0);
+                        final String lookupKey = c.getString(1);
+                        lookupUri = Contacts.getLookupUri(contactId, lookupKey);
+                    } finally {
+                        c.close();
+                    }
+                } else {
+                    final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
+                                    rawContactId);
+                    lookupUri = RawContacts.getContactLookupUri(resolver, rawContactUri);
+                }
                 Log.v(TAG, "Saved contact. New URI: " + lookupUri);
                 break;
 
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index 3d4b70f..95a39e7 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -96,6 +96,7 @@
     private TextView mReadOnlyWarningView;
     private ImageView mPhotoView;
     private ViewGroup mEditorContainerView;
+    private static WeakReference<ProgressDialog> sProgressDialog;
 
     private AccountTypeManager mAccountTypeManager;
     private ContentResolver mContentResolver;
@@ -691,7 +692,6 @@
         private static final int RESULT_FAILURE = 2;
 
         private ConfirmAddDetailActivity activityTarget;
-        private WeakReference<ProgressDialog> mProgress;
 
         private AccountTypeManager mAccountTypeManager;
 
@@ -702,8 +702,8 @@
 
         @Override
         protected void onPreExecute() {
-            mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(activityTarget, null,
-                    activityTarget.getText(R.string.savingContact)));
+            sProgressDialog = new WeakReference<ProgressDialog>(ProgressDialog.show(activityTarget,
+                    null, activityTarget.getText(R.string.savingContact)));
 
             // Before starting this task, start an empty service to protect our
             // process from being reclaimed by the system.
@@ -760,8 +760,7 @@
         protected void onPostExecute(Integer result) {
             final Context context = activityTarget;
 
-            // Dismiss the progress dialog
-            mProgress.get().dismiss();
+            dismissProgressDialog();
 
             // Show a toast message based on the success or failure of the save action.
             if (result == RESULT_SUCCESS) {
@@ -776,6 +775,24 @@
         }
     }
 
+    @Override
+    protected void onStop() {
+        super.onStop();
+        // Dismiss the progress dialog here to prevent leaking the window on orientation change.
+        dismissProgressDialog();
+    }
+
+    /**
+     * Dismiss the progress dialog (check if it is null because it is a {@link WeakReference}).
+     */
+    private static void dismissProgressDialog() {
+        ProgressDialog dialog = (sProgressDialog == null) ? null : sProgressDialog.get();
+        if (dialog != null) {
+            dialog.dismiss();
+        }
+        sProgressDialog = null;
+    }
+
     /**
      * This method is intended to be executed after the background task for saving edited info has
      * finished. The method sets the activity result (and intent if applicable) and finishes the
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 332a953..d2759dc 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -53,6 +53,7 @@
 import com.android.contacts.model.AccountWithDataSet;
 import com.android.contacts.preference.ContactsPreferenceActivity;
 import com.android.contacts.preference.DisplayOptionsPreferenceFragment;
+import com.android.contacts.util.AccountPromptUtils;
 import com.android.contacts.util.AccountSelectionUtil;
 import com.android.contacts.util.AccountsListAdapter;
 import com.android.contacts.util.Constants;
@@ -918,6 +919,16 @@
                 mAllFragment.setEnabled(true);
             }
         } else {
+            // If there are no accounts on the device and we should show the "no account" prompt
+            // (based on {@link SharedPreferences}), then launch the account setup activity so the
+            // user can sign-in or create an account.
+            if (!areAccountsAvailable() && AccountPromptUtils.shouldShowAccountPrompt(this)) {
+                AccountPromptUtils.launchAccountPrompt(this);
+                return;
+            }
+
+            // Otherwise, continue setting up the page so that the user can still use the app
+            // without an account.
             if (mAllFragment != null) {
                 mAllFragment.setEnabled(false);
             }
diff --git a/src/com/android/contacts/calllog/CallLogAdapter.java b/src/com/android/contacts/calllog/CallLogAdapter.java
index 7666a7a..4223146 100644
--- a/src/com/android/contacts/calllog/CallLogAdapter.java
+++ b/src/com/android/contacts/calllog/CallLogAdapter.java
@@ -584,7 +584,13 @@
         ExpirableCache.CachedValue<ContactInfo> cachedInfo =
                 mContactInfoCache.getCachedValue(number);
         ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue();
-        if (cachedInfo == null) {
+        if (!mPhoneNumberHelper.canPlaceCallsTo(number)
+                || mPhoneNumberHelper.isVoicemailNumber(number)) {
+            // If this is a number that cannot be dialed, there is no point in looking up a contact
+            // for it.
+            info = ContactInfo.EMPTY;
+            formattedNumber = null;
+        } else if (cachedInfo == null) {
             mContactInfoCache.put(number, ContactInfo.EMPTY);
             // Use the cached contact info from the call log.
             info = cachedContactInfo;
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index b01316b..756b1c7 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -19,7 +19,6 @@
 import com.android.contacts.R;
 
 import android.content.Context;
-import android.os.Handler;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -88,8 +87,6 @@
     private View mDetailFragmentView;
     private View mUpdatesFragmentView;
 
-    private boolean mScrollToCurrentPage = false;
-
     public ContactDetailFragmentCarousel(Context context) {
         this(context, null);
     }
@@ -144,31 +141,9 @@
                 resolveSize(screenHeight, heightMeasureSpec));
     }
 
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-        if (mScrollToCurrentPage) {
-            mScrollToCurrentPage = false;
-            // Use scrollTo() instead of smoothScrollTo() to prevent a visible flicker to the user
-            scrollTo(mCurrentPage == ABOUT_PAGE ? 0 : mAllowedHorizontalScrollLength, 0);
-            updateTouchInterceptors();
-        }
-    }
-
     /**
-     * Set the current page that should be restored when the view is first laid out.
-     */
-    public void restoreCurrentPage(int pageIndex) {
-        setCurrentPage(pageIndex);
-        // It is only possible to scroll the view after onMeasure() has been called (where the
-        // allowed horizontal scroll length is determined). Hence, set a flag that will be read
-        // in onLayout() after the children and this view have finished being laid out.
-        mScrollToCurrentPage = true;
-    }
-
-    /**
-     * Set the current page. This auto-scrolls the carousel to the current page and dims out
-     * the non-selected page.
+     * Set the current page. This dims out the non-selected page but doesn't do any scrolling of
+     * the carousel.
      */
     public void setCurrentPage(int pageIndex) {
         mCurrentPage = pageIndex;
@@ -176,7 +151,6 @@
         if (mAboutFragment != null && mUpdatesFragment != null) {
             mAboutFragment.setAlphaLayerValue(mCurrentPage == ABOUT_PAGE ? 0 : MAX_ALPHA);
             mUpdatesFragment.setAlphaLayerValue(mCurrentPage == UPDATES_PAGE ? 0 : MAX_ALPHA);
-            snapToEdge();
         }
     }
 
@@ -205,9 +179,12 @@
             mEnableSwipe = enable;
             if (mUpdatesFragmentView != null) {
                 mUpdatesFragmentView.setVisibility(enable ? View.VISIBLE : View.GONE);
-                mScrollToCurrentPage = true;
-                requestLayout();
-                invalidate();
+                if (mCurrentPage == ABOUT_PAGE) {
+                    mDetailFragmentView.requestFocus();
+                } else {
+                    mUpdatesFragmentView.requestFocus();
+                }
+                updateTouchInterceptors();
             }
         }
     }
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 7a7f400..4b31a6e 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -215,7 +215,7 @@
 
                 mFragmentCarousel.setFragmentViews(mDetailFragmentView, mUpdatesFragmentView);
                 mFragmentCarousel.setFragments(mDetailFragment, mUpdatesFragment);
-                mFragmentCarousel.restoreCurrentPage(currentPageIndex);
+                mFragmentCarousel.setCurrentPage(currentPageIndex);
                 break;
             }
         }
diff --git a/src/com/android/contacts/util/AccountPromptUtils.java b/src/com/android/contacts/util/AccountPromptUtils.java
new file mode 100644
index 0000000..58865d0
--- /dev/null
+++ b/src/com/android/contacts/util/AccountPromptUtils.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ * 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.contacts.util;
+
+import com.android.contacts.R;
+import com.android.contacts.model.GoogleAccountType;
+
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Utility class for controlling whether the standard "no account" prompt on launch is shown.
+ */
+public class AccountPromptUtils {
+
+    private static final String TAG = AccountPromptUtils.class.getSimpleName();
+
+    /** {@link SharedPreferences} key for whether or not the "no account" prompt should be shown. */
+    private static final String KEY_SHOW_ACCOUNT_PROMPT = "settings.showAccountPrompt";
+
+    /**
+     * The following intent keys are understood by the {@link AccountManager} and should not be
+     * changed unless the API changes.
+     */
+    private static final String KEY_INTRO_MESSAGE = "introMessage";
+    private static final String KEY_ALLOW_SKIP_ACCOUNT_SETUP = "allowSkip";
+    private static final String KEY_USER_SKIPPED_ACCOUNT_SETUP = "setupSkipped";
+
+    private static SharedPreferences getSharedPreferences(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context);
+    }
+
+    /**
+     * Returns true if the "no account" prompt should be shown
+     * (according to {@link SharedPreferences}), otherwise return false.
+     */
+    public static boolean shouldShowAccountPrompt(Context context) {
+        return getSharedPreferences(context).getBoolean(KEY_SHOW_ACCOUNT_PROMPT, true);
+    }
+
+    /**
+     * Remember to never show the "no account" prompt again by saving this to
+     * {@link SharedPreferences}.
+     */
+    public static void neverShowAccountPromptAgain(Context context) {
+        getSharedPreferences(context).edit()
+                .putBoolean(KEY_SHOW_ACCOUNT_PROMPT, false)
+                .apply();
+    }
+
+    /**
+     * Launch the "no account" prompt. (We assume the caller has already verified that the prompt
+     * can be shown, so checking the {@link #KEY_SHOW_ACCOUNT_PROMPT} value in
+     * {@link SharedPreferences} will not be done in this method).
+     */
+    public static void launchAccountPrompt(Activity activity) {
+        Bundle options = new Bundle();
+        options.putCharSequence(KEY_INTRO_MESSAGE, activity.getString(R.string.no_account_prompt));
+        options.putBoolean(KEY_ALLOW_SKIP_ACCOUNT_SETUP, true);
+        AccountManager.get(activity).addAccount(GoogleAccountType.ACCOUNT_TYPE, null, null, options,
+                activity, getAccountManagerCallback(activity), null);
+    }
+
+    private static AccountManagerCallback<Bundle> getAccountManagerCallback(
+            final Activity activity) {
+        return new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> future) {
+                if (future.isCancelled()) {
+                    // The account creation process was canceled
+                    activity.finish();
+                    return;
+                }
+                try {
+                    Bundle result = future.getResult();
+                    if (result.getBoolean(KEY_USER_SKIPPED_ACCOUNT_SETUP)) {
+                        AccountPromptUtils.neverShowAccountPromptAgain(activity);
+                    }
+                } catch (OperationCanceledException ignore) {
+                    Log.e(TAG, "Account setup error: account creation process canceled");
+                } catch (IOException ignore) {
+                    Log.e(TAG, "Account setup error: No authenticator was registered for this"
+                            + "account type or the authenticator failed to respond");
+                } catch (AuthenticatorException ignore) {
+                    Log.e(TAG, "Account setup error: Authenticator experienced an I/O problem");
+                }
+            }
+        };
+    }
+}
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index 054e018..18b9cc1 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -45,18 +45,14 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.res.Configuration;
+import android.database.Cursor;
 import android.net.Uri;
-import android.nfc.NdefMessage;
-import android.nfc.NdefRecord;
-import android.nfc.NfcAdapter;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
 import android.os.PowerManager;
-import android.os.RemoteException;
+import android.provider.OpenableColumns;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.TextUtils;
@@ -72,7 +68,6 @@
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
-import java.nio.charset.Charset;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -285,6 +280,8 @@
                         return;
                     }
                 } else {
+                    final ContentResolver resolver =
+                            ImportVCardActivity.this.getContentResolver();
                     for (Uri sourceUri : mSourceUris) {
                         String filename = null;
                         // Note: caches are removed by VCardService.
@@ -309,10 +306,37 @@
                             Log.w(LOG_TAG, "destUri is null");
                             break;
                         }
+
+                        String displayName = null;
+                        Cursor cursor = null;
+                        // Try to get a display name from the given Uri. If it fails, we just
+                        // pick up the last part of the Uri.
+                        try {
+                            cursor = resolver.query(sourceUri,
+                                    new String[] { OpenableColumns.DISPLAY_NAME },
+                                    null, null, null);
+                            if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
+                                if (cursor.getCount() > 1) {
+                                    Log.w(LOG_TAG, "Unexpected multiple rows: "
+                                            + cursor.getCount());
+                                }
+                                int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+                                if (index >= 0) {
+                                    displayName = cursor.getString(index);
+                                }
+                            }
+                        } finally {
+                            if (cursor != null) {
+                                cursor.close();
+                            }
+                        }
+                        if (TextUtils.isEmpty(displayName)){
+                            displayName = sourceUri.getLastPathSegment();
+                        }
+
                         final ImportRequest request;
                         try {
-                            request = constructImportRequest(null, localDataUri,
-                                    sourceUri.getLastPathSegment());
+                            request = constructImportRequest(null, localDataUri, displayName);
                         } catch (VCardException e) {
                             Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
                             showFailureNotification(R.string.fail_reason_not_supported);