Merge "Allow adding/replacing a photo from contact card."
diff --git a/res/layout-sw580dp/join_contact_picker.xml b/res/layout-sw580dp/join_contact_picker.xml
new file mode 100644
index 0000000..3d9127b
--- /dev/null
+++ b/res/layout-sw580dp/join_contact_picker.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.widget.FullHeightLinearLayout"
+    style="@style/ContactPickerLayout"
+    android:orientation="vertical">
+    <!-- See also comments in contact_picker.xml -->
+    <view
+        class="android.widget.SearchView"
+        android:id="@+id/search_view"
+        android:layout_width="match_parent"
+        android:maxWidth="@dimen/contact_picker_search_view_max_width"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="0dip"
+        android:layout_marginRight="@dimen/list_visible_scrollbar_padding"
+        android:paddingRight="0dip"
+        android:iconifiedByDefault="false" />
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:id="@+id/list_container" />
+</view>
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 13124f2..7498f5a 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -162,16 +162,22 @@
                     <TextView android:id="@+id/call_and_sms_text"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
+                        android:paddingRight="@dimen/call_log_icon_margin"
                         android:textAppearance="?android:attr/textAppearanceMedium"
                         android:textColor="?attr/call_log_primary_text_color"
+                        android:singleLine="true"
+                        android:ellipsize="end"
                     />
 
                     <TextView android:id="@+id/call_and_sms_label"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
+                        android:paddingRight="@dimen/call_log_icon_margin"
                         android:textAppearance="?android:attr/textAppearanceSmall"
                         android:textColor="?attr/call_log_primary_text_color"
                         android:textAllCaps="true"
+                        android:singleLine="true"
+                        android:ellipsize="end"
                     />
 
                 </LinearLayout>
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 777c7af..4040c28 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -69,18 +69,38 @@
                     android:id="@+id/name"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:layout_marginRight="@dimen/call_log_icon_margin"
                     android:textColor="?attr/call_log_primary_text_color"
                     android:textSize="18sp"
                     android:singleLine="true"
                 />
-                <TextView
-                    android:id="@+id/number"
+                <LinearLayout
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:textColor="?attr/call_log_secondary_text_color"
-                    android:textSize="14sp"
-                    android:singleLine="true"
-                />
+                    android:orientation="horizontal"
+                >
+                    <TextView
+                        android:id="@+id/number"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginRight="@dimen/call_log_icon_margin"
+                        android:textColor="?attr/call_log_secondary_text_color"
+                        android:textSize="14sp"
+                        android:singleLine="true"
+                        android:ellipsize="marquee"
+                        />
+                    <TextView
+                        android:id="@+id/label"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginRight="@dimen/call_log_icon_margin"
+                        android:textColor="?attr/call_log_secondary_text_color"
+                        android:textStyle="bold"
+                        android:textSize="14sp"
+                        android:singleLine="true"
+                        android:ellipsize="marquee"
+                        />
+                    </LinearLayout>
                 <LinearLayout
                     android:id="@+id/call_type"
                     android:layout_width="wrap_content"
@@ -99,6 +119,7 @@
                         android:id="@+id/call_count_and_date"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
+                        android:layout_marginRight="@dimen/call_log_icon_margin"
                         android:layout_gravity="center_vertical"
                         android:textColor="?attr/call_log_secondary_text_color"
                         android:textSize="14sp"
diff --git a/res/layout/join_contact_picker.xml b/res/layout/join_contact_picker.xml
index ea0deaf..ee30525 100644
--- a/res/layout/join_contact_picker.xml
+++ b/res/layout/join_contact_picker.xml
@@ -14,23 +14,13 @@
      limitations under the License.
 -->
 
-<view
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<view xmlns:android="http://schemas.android.com/apk/res/android"
     class="com.android.contacts.widget.FullHeightLinearLayout"
     style="@style/ContactPickerLayout"
     android:orientation="vertical">
-
     <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="0dip"
         android:layout_weight="1"
         android:id="@+id/list_container" />
-
-    <View
-        android:id="@+id/divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dip"
-        android:layout_marginLeft="?attr/contact_browser_list_padding_left"
-        android:layout_marginRight="?attr/contact_browser_list_padding_right"
-        android:background="?android:attr/dividerHorizontal" />
 </view>
diff --git a/res/menu/phone_favorite_options.xml b/res/menu/phone_favorite_options.xml
new file mode 100644
index 0000000..ac67d6e
--- /dev/null
+++ b/res/menu/phone_favorite_options.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/menu_import_export"
+        android:title="@string/menu_import_export" />
+
+    <item
+        android:id="@+id/menu_accounts"
+        android:title="@string/menu_accounts" />
+</menu>
diff --git a/res/values-sw580dp/styles.xml b/res/values-sw580dp/styles.xml
index bf5b137..70e2a3b 100644
--- a/res/values-sw580dp/styles.xml
+++ b/res/values-sw580dp/styles.xml
@@ -95,6 +95,8 @@
     <style name="JoinContactActivityTheme" parent="ContactPickerTheme" >
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
+        <!-- In the contact picker screen we're using adjustResize but we don't want it here. -->
+        <item name="android:windowSoftInputMode">adjustUnspecified</item>
     </style>
 
     <style name="ContactListFilterTheme" parent="@android:Theme.Holo.Light.Dialog">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 225c9fe..ed916e6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -100,8 +100,8 @@
     <!-- Menu item used to view the details for a specific contact -->
     <string name="menu_viewContact">View contact</string>
 
-    <!-- Menu item used to call a contact, containing the name of the contact to call -->
-    <string name="menu_callNumber">Call <xliff:g id="name">%s</xliff:g></string>
+    <!-- Menu item used to call a contact, containing the number of the contact to call -->
+    <string name="menu_callNumber">Call <xliff:g id="number">%s</xliff:g></string>
 
     <!-- Menu item used to add a star to a contact, which makes that contact show up at the top of favorites -->
     <string name="menu_addStar">Add to favorites</string>
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index caa8bce..6224d19 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -22,6 +22,7 @@
 import com.android.contacts.calllog.ContactInfo;
 import com.android.contacts.calllog.ContactInfoHelper;
 import com.android.contacts.calllog.PhoneNumberHelper;
+import com.android.contacts.format.FormatUtils;
 import com.android.contacts.util.AsyncTaskExecutor;
 import com.android.contacts.util.AsyncTaskExecutors;
 import com.android.contacts.voicemail.VoicemailPlaybackFragment;
@@ -469,7 +470,8 @@
                                     firstDetails.number, firstDetails.formattedNumber);
 
                     ViewEntry entry = new ViewEntry(
-                            getString(R.string.menu_callNumber, displayNumber),
+                            getString(R.string.menu_callNumber,
+                                    FormatUtils.forceLeftToRight(displayNumber)),
                             new Intent(Intent.ACTION_CALL_PRIVILEGED, numberCallUri),
                             getString(R.string.description_call, nameOrNumber));
 
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index 2d75c26..60dfb7b 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -18,7 +18,6 @@
 
 import com.android.contacts.calllog.CallTypeHelper;
 import com.android.contacts.calllog.PhoneNumberHelper;
-import com.android.contacts.format.FormatUtils;
 
 import android.content.res.Resources;
 import android.graphics.Typeface;
@@ -103,6 +102,7 @@
 
         final CharSequence nameText;
         final CharSequence numberText;
+        final CharSequence labelText;
         final CharSequence displayNumber =
             mPhoneNumberHelper.getDisplayNumber(details.number, details.formattedNumber);
         if (TextUtils.isEmpty(details.name)) {
@@ -113,20 +113,17 @@
             } else {
                 numberText = details.geocode;
             }
+            labelText = null;
         } else {
             nameText = details.name;
-            if (numberFormattedLabel != null) {
-                numberText = FormatUtils.applyStyleToSpan(Typeface.BOLD,
-                        numberFormattedLabel + " " + displayNumber, 0,
-                        numberFormattedLabel.length(),
-                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-            } else {
-                numberText = displayNumber;
-            }
+            numberText = displayNumber;
+            labelText = numberFormattedLabel;
         }
 
         views.nameView.setText(nameText);
         views.numberView.setText(numberText);
+        views.labelView.setText(labelText);
+        views.labelView.setVisibility(TextUtils.isEmpty(labelText) ? View.GONE : View.VISIBLE);
     }
 
     /** Sets the text of the header view for the details page of a phone call. */
diff --git a/src/com/android/contacts/PhoneCallDetailsViews.java b/src/com/android/contacts/PhoneCallDetailsViews.java
index fa06879..ea5a461 100644
--- a/src/com/android/contacts/PhoneCallDetailsViews.java
+++ b/src/com/android/contacts/PhoneCallDetailsViews.java
@@ -31,14 +31,17 @@
     public final CallTypeIconsView callTypeIcons;
     public final TextView callTypeAndDate;
     public final TextView numberView;
+    public final TextView labelView;
 
     private PhoneCallDetailsViews(TextView nameView, View callTypeView,
-            CallTypeIconsView callTypeIcons, TextView callTypeAndDate, TextView numberView) {
+            CallTypeIconsView callTypeIcons, TextView callTypeAndDate, TextView numberView,
+            TextView labelView) {
         this.nameView = nameView;
         this.callTypeView = callTypeView;
         this.callTypeIcons = callTypeIcons;
         this.callTypeAndDate = callTypeAndDate;
         this.numberView = numberView;
+        this.labelView = labelView;
     }
 
     /**
@@ -53,7 +56,8 @@
                 view.findViewById(R.id.call_type),
                 (CallTypeIconsView) view.findViewById(R.id.call_type_icons),
                 (TextView) view.findViewById(R.id.call_count_and_date),
-                (TextView) view.findViewById(R.id.number));
+                (TextView) view.findViewById(R.id.number),
+                (TextView) view.findViewById(R.id.label));
     }
 
     public static PhoneCallDetailsViews createForTest(Context context) {
@@ -62,6 +66,7 @@
                 new View(context),
                 new CallTypeIconsView(context),
                 new TextView(context),
+                new TextView(context),
                 new TextView(context));
     }
 }
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index b5b6c1d..4b59d34 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -107,7 +107,7 @@
         if (savedState != null) {
             mActionCode = savedState.getInt(KEY_ACTION_CODE);
         }
-
+        
         // Extract relevant information from the intent
         mRequest = mIntentResolver.resolveIntent(getIntent());
         if (!mRequest.isValid()) {
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index a997aa0..d4a96e1 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -566,6 +566,9 @@
                     && mContactListFilterController.getFilter() != null) {
                 mPhoneFavoriteFragment.setFilter(mContactListFilterController.getFilter());
             }
+            if (currentPosition == TAB_INDEX_FAVORITES) {
+                mPhoneFavoriteFragment.onVisibilityChanged(true);
+            }
         } else if (fragment instanceof PhoneNumberPickerFragment) {
             mSearchFragment = (PhoneNumberPickerFragment) fragment;
             mSearchFragment.setOnPhoneNumberPickerActionListener(mPhoneNumberPickerActionListener);
@@ -817,7 +820,7 @@
         final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
         final MenuItem addContactOptionMenuItem = menu.findItem(R.id.add_contact);
         final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        Tab tab = getActionBar().getSelectedTab();
+        final Tab tab = getActionBar().getSelectedTab();
         if (mInSearchUi) {
             searchMenuItem.setVisible(false);
             if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
diff --git a/src/com/android/contacts/activities/JoinContactActivity.java b/src/com/android/contacts/activities/JoinContactActivity.java
index 75a13d0..4a277cb 100644
--- a/src/com/android/contacts/activities/JoinContactActivity.java
+++ b/src/com/android/contacts/activities/JoinContactActivity.java
@@ -24,18 +24,29 @@
 import com.android.contacts.list.OnContactPickerActionListener;
 
 import android.app.ActionBar;
+import android.app.ActionBar.LayoutParams;
 import android.app.Fragment;
+import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract;
+import android.text.TextUtils;
 import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.SearchView;
+import android.widget.SearchView.OnCloseListener;
+import android.widget.SearchView.OnQueryTextListener;
 
 /**
  * An activity that shows a list of contacts that can be joined with the target contact.
  */
-public class JoinContactActivity extends ContactsActivity {
+public class JoinContactActivity extends ContactsActivity
+        implements OnQueryTextListener, OnCloseListener, OnFocusChangeListener {
 
     private static final String TAG = "JoinContactActivity";
 
@@ -59,6 +70,7 @@
     private long mTargetContactId;
 
     private JoinContactListFragment mListFragment;
+    private SearchView mSearchView;
 
     @Override
     public void onAttachFragment(Fragment fragment) {
@@ -93,12 +105,7 @@
                     .commitAllowingStateLoss();
         }
 
-        final ActionBar actionBar = getActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayShowHomeEnabled(true);
-            actionBar.setDisplayHomeAsUpEnabled(true);
-            actionBar.setDisplayShowTitleEnabled(true);
-        }
+        prepareSearchViewAndActionBar();
     }
 
     private void setupActionListener() {
@@ -125,6 +132,74 @@
         });
     }
 
+    private void prepareSearchViewAndActionBar() {
+        final ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            final View searchViewOnLayout = findViewById(R.id.search_view);
+            if (searchViewOnLayout != null) {
+                searchViewOnLayout.setVisibility(View.GONE);
+            }
+
+            final View searchViewLayout = LayoutInflater.from(actionBar.getThemedContext())
+                    .inflate(R.layout.custom_action_bar, null);
+            mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view);
+
+            // In order to make the SearchView look like "shown via search menu", we need to
+            // manually setup its state. See also DialtactsActivity.java and ActionBarAdapter.java.
+            mSearchView.setIconifiedByDefault(true);
+            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
+            mSearchView.setIconified(false);
+
+            mSearchView.setOnQueryTextListener(this);
+            mSearchView.setOnCloseListener(this);
+            mSearchView.setOnQueryTextFocusChangeListener(this);
+
+            actionBar.setCustomView(searchViewLayout,
+                    new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+            actionBar.setDisplayShowCustomEnabled(true);
+            actionBar.setDisplayShowHomeEnabled(true);
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        } else {
+            mSearchView = (SearchView) findViewById(R.id.search_view);
+            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
+            mSearchView.setOnQueryTextListener(this);
+            mSearchView.setOnQueryTextFocusChangeListener(this);
+        }
+
+        // Clear focus and suppress keyboard show-up.
+        mSearchView.clearFocus();
+    }
+
+    @Override
+    public boolean onQueryTextChange(String newText) {
+        mListFragment.setQueryString(newText, true);
+        return false;
+    }
+
+    @Override
+    public boolean onQueryTextSubmit(String query) {
+        return false;
+    }
+
+    @Override
+    public boolean onClose() {
+        if (!TextUtils.isEmpty(mSearchView.getQuery())) {
+            mSearchView.setQuery(null, true);
+        }
+        return true;
+    }
+
+    @Override
+    public void onFocusChange(View view, boolean hasFocus) {
+        switch (view.getId()) {
+            case R.id.search_view: {
+                if (hasFocus) {
+                    showInputMethod(mSearchView.findFocus());
+                }
+            }
+        }
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
@@ -156,4 +231,14 @@
             mListFragment.onPickerResult(data);
         }
     }
+
+    private void showInputMethod(View view) {
+        final InputMethodManager imm = (InputMethodManager)
+                getSystemService(Context.INPUT_METHOD_SERVICE);
+        if (imm != null) {
+            if (!imm.showSoftInput(view, 0)) {
+                Log.w(TAG, "Failed to show soft input method.");
+            }
+        }
+    }
 }
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index ba1e257..3ba241d 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -90,6 +90,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ListPopupWindow;
@@ -823,7 +824,7 @@
         }
 
         @Override
-        public void startUpdate(View container) {
+        public void startUpdate(ViewGroup container) {
         }
 
         private Fragment getFragment(int position) {
@@ -844,7 +845,7 @@
         }
 
         @Override
-        public Object instantiateItem(View container, int position) {
+        public Object instantiateItem(ViewGroup container, int position) {
             if (mCurTransaction == null) {
                 mCurTransaction = mFragmentManager.beginTransaction();
             }
@@ -857,7 +858,7 @@
         }
 
         @Override
-        public void destroyItem(View container, int position, Object object) {
+        public void destroyItem(ViewGroup container, int position, Object object) {
             if (mCurTransaction == null) {
                 mCurTransaction = mFragmentManager.beginTransaction();
             }
@@ -865,7 +866,7 @@
         }
 
         @Override
-        public void finishUpdate(View container) {
+        public void finishUpdate(ViewGroup container) {
             if (mCurTransaction != null) {
                 mCurTransaction.commitAllowingStateLoss();
                 mCurTransaction = null;
@@ -879,7 +880,7 @@
         }
 
         @Override
-        public void setPrimaryItem(View container, int position, Object object) {
+        public void setPrimaryItem(ViewGroup container, int position, Object object) {
             Fragment fragment = (Fragment) object;
             if (mCurrentPrimaryItem != fragment) {
                 if (mCurrentPrimaryItem != null) {
@@ -968,7 +969,12 @@
         View mainView = findViewById(R.id.main_view);
 
         if (mProviderStatus == ProviderStatus.STATUS_NORMAL) {
+            // Ensure that the mTabPager is visible; we may have made it invisible below.
             contactsUnavailableView.setVisibility(View.GONE);
+            if (mTabPager != null) {
+                mTabPager.setVisibility(View.VISIBLE);
+            }
+
             if (mainView != null) {
                 mainView.setVisibility(View.VISIBLE);
             }
@@ -1001,7 +1007,14 @@
             } else {
                 mContactsUnavailableFragment.update();
             }
+
+            // Show the contactsUnavailableView, and hide the mTabPager so that we don't
+            // see it sliding in underneath the contactsUnavailableView at the edges.
             contactsUnavailableView.setVisibility(View.VISIBLE);
+            if (mTabPager != null) {
+                mTabPager.setVisibility(View.GONE);
+            }
+
             if (mainView != null) {
                 mainView.setVisibility(View.INVISIBLE);
             }
diff --git a/src/com/android/contacts/calllog/CallLogAdapter.java b/src/com/android/contacts/calllog/CallLogAdapter.java
index ea282fc..99ba8e8 100644
--- a/src/com/android/contacts/calllog/CallLogAdapter.java
+++ b/src/com/android/contacts/calllog/CallLogAdapter.java
@@ -650,9 +650,15 @@
             return;
         }
 
-        mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
-                Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?",
-                new String[]{ number, countryIso });
+        if (countryIso == null) {
+            mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
+                    Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL",
+                    new String[]{ number });
+        } else {
+            mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
+                    Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?",
+                    new String[]{ number, countryIso });
+        }
     }
 
     /** Returns the contact information as stored in the call log. */
diff --git a/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java b/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
index c5e8f91..59dfcd4 100644
--- a/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
+++ b/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
@@ -90,8 +90,13 @@
         // TODO: Move this into a service, to avoid holding the receiver up.
         final NewCall[] newCalls = mNewCallsQuery.query();
 
+        if (newCalls == null) {
+            // Query failed, just return.
+            return;
+        }
+
         if (newCalls.length == 0) {
-            Log.e(TAG, "No voicemails to notify about: clear the notification.");
+            // No voicemails to notify about: clear the notification.
             clearNotification();
             return;
         }
@@ -243,6 +248,9 @@
             try {
                 cursor = mContentResolver.query(Calls.CONTENT_URI_WITH_VOICEMAIL, PROJECTION,
                         selection, selectionArgs, Calls.DEFAULT_SORT_ORDER);
+                if (cursor == null) {
+                    return null;
+                }
                 NewCall[] newCalls = new NewCall[cursor.getCount()];
                 while (cursor.moveToNext()) {
                     newCalls[cursor.getPosition()] = createNewCallsFromCursor(cursor);
@@ -301,7 +309,7 @@
                 cursor = mContentResolver.query(
                         Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
                         PROJECTION, null, null, null);
-                if (!cursor.moveToFirst()) return null;
+                if (cursor == null || !cursor.moveToFirst()) return null;
                 return cursor.getString(DISPLAY_NAME_COLUMN_INDEX);
             } finally {
                 if (cursor != null) {
diff --git a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
index edcfc39..c708dc8 100644
--- a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
+++ b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
@@ -19,6 +19,7 @@
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * Adapter for the {@link ViewPager} for the contact detail page for a contact in 2 cases:
@@ -88,11 +89,11 @@
     }
 
     @Override
-    public void startUpdate(View container) {
+    public void startUpdate(ViewGroup container) {
     }
 
     @Override
-    public Object instantiateItem(View container, int position) {
+    public Object instantiateItem(ViewGroup container, int position) {
         switch (position) {
             case INDEX_ABOUT_FRAGMENT:
                 mAboutFragmentView.setVisibility(View.VISIBLE);
@@ -105,12 +106,12 @@
     }
 
     @Override
-    public void destroyItem(View container, int position, Object object) {
+    public void destroyItem(ViewGroup container, int position, Object object) {
         ((View) object).setVisibility(View.GONE);
     }
 
     @Override
-    public void finishUpdate(View container) {
+    public void finishUpdate(ViewGroup container) {
     }
 
     @Override
diff --git a/src/com/android/contacts/format/FormatUtils.java b/src/com/android/contacts/format/FormatUtils.java
index 4b076cf..82bf78d 100644
--- a/src/com/android/contacts/format/FormatUtils.java
+++ b/src/com/android/contacts/format/FormatUtils.java
@@ -28,6 +28,8 @@
  * Assorted utility methods related to text formatting in Contacts.
  */
 public class FormatUtils {
+    private static final char LEFT_TO_RIGHT_EMBEDDING = '\u202A';
+    private static final char POP_DIRECTIONAL_FORMATTING = '\u202C';
 
     /**
      * Finds the earliest point in buffer1 at which the first part of buffer2 matches.  For example,
@@ -180,4 +182,13 @@
 
         return -1;
     }
+
+    /** Returns the given text, forced to be left-to-right. */
+    public static CharSequence forceLeftToRight(CharSequence text) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(LEFT_TO_RIGHT_EMBEDDING);
+        sb.append(text);
+        sb.append(POP_DIRECTIONAL_FORMATTING);
+        return sb.toString();
+    }
 }
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index cf86dc9..d95a1bc 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -131,6 +131,28 @@
         return partition;
     }
 
+    /**
+     * Remove all directories after the default directory. This is typically used when contacts
+     * list screens are asked to exit the search mode and thus need to remove all remote directory
+     * results for the search.
+     *
+     * This code assumes that the default directory and directories before that should not be
+     * deleted (e.g. Join screen has "suggested contacts" directory before the default director,
+     * and we should not remove the directory).
+     */
+    /* package */ void removeDirectoriesAfterDefault() {
+        final int partitionCount = getPartitionCount();
+        for (int i = partitionCount - 1; i >= 0; i--) {
+            final Partition partition = getPartition(i);
+            if ((partition instanceof DirectoryPartition)
+                    && ((DirectoryPartition) partition).getDirectoryId() == Directory.DEFAULT) {
+                break;
+            } else {
+                removePartition(i);
+            }
+        }
+    }
+
     private int getPartitionByDirectoryId(long id) {
         int count = getPartitionCount();
         for (int i = 0; i < count; i++) {
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 8db477e..5ee25a2 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -613,12 +613,10 @@
 
                 mAdapter.clearPartitions();
                 if (!flag) {
-                    // If we are switching from search to regular display,
-                    // remove all directory partitions (except the default one).
-                    int count = mAdapter.getPartitionCount();
-                    for (int i = count; --i >= 1;) {
-                        mAdapter.removePartition(i);
-                    }
+                    // If we are switching from search to regular display, remove all directory
+                    // partitions after default one, assuming they are remote directories which
+                    // should be cleaned up on exiting the search mode.
+                    mAdapter.removeDirectoriesAfterDefault();
                 }
                 mAdapter.configureDefaultPartition(false, flag);
             }
diff --git a/src/com/android/contacts/list/JoinContactListAdapter.java b/src/com/android/contacts/list/JoinContactListAdapter.java
index bfe8c53..80ddc83 100644
--- a/src/com/android/contacts/list/JoinContactListAdapter.java
+++ b/src/com/android/contacts/list/JoinContactListAdapter.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.CursorLoader;
 import android.database.Cursor;
-import android.database.MatrixCursor;
 import android.net.Uri;
 import android.net.Uri.Builder;
 import android.provider.ContactsContract;
@@ -53,7 +52,6 @@
 
     @Override
     protected void addPartitions() {
-
         // Partition 0: suggestions
         addPartition(false, true);
 
@@ -69,11 +67,11 @@
     public void configureLoader(CursorLoader cursorLoader, long directoryId) {
         JoinContactLoader loader = (JoinContactLoader) cursorLoader;
 
-        Builder builder = Contacts.CONTENT_URI.buildUpon();
+        final Builder builder = Contacts.CONTENT_URI.buildUpon();
         builder.appendEncodedPath(String.valueOf(mTargetContactId));
         builder.appendEncodedPath(AggregationSuggestions.CONTENT_DIRECTORY);
 
-        String filter = getQueryString();
+        final String filter = getQueryString();
         if (!TextUtils.isEmpty(filter)) {
             builder.appendEncodedPath(Uri.encode(filter));
         }
@@ -84,13 +82,22 @@
 
         // TODO simplify projection
         loader.setProjection(getProjection(false));
-        Uri allContactsUri = buildSectionIndexerUri(Contacts.CONTENT_URI).buildUpon()
+        final Uri allContactsUri;
+        if (!TextUtils.isEmpty(filter)) {
+            allContactsUri = buildSectionIndexerUri(Contacts.CONTENT_FILTER_URI).buildUpon()
+                .appendEncodedPath(Uri.encode(filter))
                 .appendQueryParameter(
                         ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
                 .build();
+        } else {
+            allContactsUri = buildSectionIndexerUri(Contacts.CONTENT_URI).buildUpon()
+                .appendQueryParameter(
+                        ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
+                .build();
+        }
         loader.setUri(allContactsUri);
         loader.setSelection(Contacts._ID + "!=?");
-        loader.setSelectionArgs(new String[]{String.valueOf(mTargetContactId)});
+        loader.setSelectionArgs(new String[]{ String.valueOf(mTargetContactId) });
         if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
             loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
         } else {
@@ -120,7 +127,7 @@
 
     @Override
     public int getViewTypeCount() {
-        return super.getViewTypeCount() + 1;
+        return super.getViewTypeCount();
     }
 
     @Override
@@ -173,14 +180,14 @@
     protected void bindView(View itemView, int partition, Cursor cursor, int position) {
         switch (partition) {
             case PARTITION_SUGGESTIONS: {
-                final ContactListItemView view = (ContactListItemView)itemView;
+                final ContactListItemView view = (ContactListItemView) itemView;
                 view.setSectionHeader(null);
                 bindPhoto(view, partition, cursor);
                 bindName(view, cursor);
                 break;
             }
             case PARTITION_ALL_CONTACTS: {
-                final ContactListItemView view = (ContactListItemView)itemView;
+                final ContactListItemView view = (ContactListItemView) itemView;
                 bindSectionHeaderAndDivider(view, position, cursor);
                 bindPhoto(view, partition, cursor);
                 bindName(view, cursor);
diff --git a/src/com/android/contacts/list/JoinContactListFragment.java b/src/com/android/contacts/list/JoinContactListFragment.java
index 5b27bdf..7c6767b 100644
--- a/src/com/android/contacts/list/JoinContactListFragment.java
+++ b/src/com/android/contacts/list/JoinContactListFragment.java
@@ -26,6 +26,7 @@
 import android.database.Cursor;
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -103,7 +104,10 @@
         configureAdapter();
 
         getLoaderManager().initLoader(DISPLAY_NAME_LOADER, null, mLoaderCallbacks);
-        getLoaderManager().initLoader(JoinContactListAdapter.PARTITION_ALL_CONTACTS,
+
+        // When this method is called, Uri to be used may be changed. We should use restartLoader()
+        // to load the parameter again.
+        getLoaderManager().restartLoader(JoinContactListAdapter.PARTITION_ALL_CONTACTS,
                 null, mLoaderCallbacks);
     }
 
@@ -167,4 +171,11 @@
             mTargetContactId = savedState.getLong(KEY_TARGET_CONTACT_ID);
         }
     }
+
+    @Override
+    public void setQueryString(String queryString, boolean delaySelection) {
+        super.setQueryString(queryString, delaySelection);
+
+        setSearchMode(!TextUtils.isEmpty(queryString));
+    }
 }
diff --git a/src/com/android/contacts/list/JoinContactLoader.java b/src/com/android/contacts/list/JoinContactLoader.java
index 2f1f9b0..c43560e 100644
--- a/src/com/android/contacts/list/JoinContactLoader.java
+++ b/src/com/android/contacts/list/JoinContactLoader.java
@@ -20,6 +20,7 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.Uri;
+import android.util.Log;
 
 /**
  * A specialized loader for the Join Contacts UI.  It executes two queries:
@@ -29,7 +30,7 @@
 
     private String[] mProjection;
     private Uri mSuggestionUri;
-    private MatrixCursor mSuggestionsCursor;
+    private Cursor mSuggestionsCursor;
 
     public JoinContactLoader(Context context) {
         super(context, null, null, null, null, null);
@@ -53,28 +54,8 @@
     public Cursor loadInBackground() {
         // First execute the suggestions query, then call super.loadInBackground
         // to load the entire list
-        mSuggestionsCursor = loadSuggestions();
+        mSuggestionsCursor = getContext().getContentResolver()
+                .query(mSuggestionUri, mProjection, null, null, null);
         return super.loadInBackground();
     }
-
-    /**
-     * Loads join suggestions into a MatrixCursor.
-     */
-    private MatrixCursor loadSuggestions() {
-        Cursor cursor = getContext().getContentResolver().query(mSuggestionUri, mProjection,
-                null, null, null);
-        try {
-            MatrixCursor matrix = new MatrixCursor(mProjection);
-            Object[] row = new Object[mProjection.length];
-            while (cursor.moveToNext()) {
-                for (int i = 0; i < row.length; i++) {
-                    row[i] = cursor.getString(i);
-                }
-                matrix.addRow(row);
-            }
-            return matrix;
-        } finally {
-            cursor.close();
-        }
-    }
 }
\ No newline at end of file
diff --git a/src/com/android/contacts/list/PhoneFavoriteFragment.java b/src/com/android/contacts/list/PhoneFavoriteFragment.java
index af06995..b512bf1 100644
--- a/src/com/android/contacts/list/PhoneFavoriteFragment.java
+++ b/src/com/android/contacts/list/PhoneFavoriteFragment.java
@@ -18,6 +18,8 @@
 import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.ContactTileLoaderFactory;
 import com.android.contacts.R;
+import com.android.contacts.activities.DialtactsActivity.ViewPagerVisibilityListener;
+import com.android.contacts.interactions.ImportExportDialogFragment;
 import com.android.contacts.preference.ContactsPreferences;
 import com.android.contacts.util.AccountFilterUtil;
 
@@ -32,9 +34,15 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Directory;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -53,7 +61,8 @@
  * {@link PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}.
  * A contact filter header is also inserted between those adapters' results.
  */
-public class PhoneFavoriteFragment extends Fragment implements OnItemClickListener {
+public class PhoneFavoriteFragment extends Fragment implements OnItemClickListener,
+        ViewPagerVisibilityListener{
     private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
     private static final boolean DEBUG = false;
 
@@ -215,12 +224,15 @@
             new ContactsPreferenceChangeListener();
     private final ScrollListener mScrollListener = new ScrollListener();
 
+    private boolean mShowOptionsMenu;
+
     @Override
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
         if (savedState != null) {
             mFilter = savedState.getParcelable(KEY_FILTER);
         }
+        setHasOptionsMenu(true);
     }
 
     @Override
@@ -319,6 +331,32 @@
     }
 
     @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        if (mShowOptionsMenu) {
+            inflater.inflate(R.menu.phone_favorite_options, menu);
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_import_export:
+                ImportExportDialogFragment.show(getFragmentManager());
+                return true;
+            case R.id.menu_accounts:
+                final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+                intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
+                    ContactsContract.AUTHORITY
+                });
+                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                startActivity(intent);
+                return true;
+        }
+        return false;
+    }
+
+    @Override
     public void onStart() {
         super.onStart();
 
@@ -453,4 +491,9 @@
     public void setListener(Listener listener) {
         mListener = listener;
     }
+
+    @Override
+    public void onVisibilityChanged(boolean visible) {
+        mShowOptionsMenu = visible;
+    }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/contacts/activities/PeopleActivityTest.java b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
index 66c2c5a..ea7c3dc 100644
--- a/tests/src/com/android/contacts/activities/PeopleActivityTest.java
+++ b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
@@ -48,7 +48,7 @@
 import android.provider.ContactsContract.ProviderStatus;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.Smoke;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.TextView;
 
 /**
@@ -64,7 +64,7 @@
  *     -w com.android.contacts.tests/android.test.InstrumentationTestRunner
  *
  */
-@Smoke
+@SmallTest
 public class PeopleActivityTest
         extends ActivityInstrumentationTestCase2<PeopleActivity>
 {
diff --git a/tests/src/com/android/contacts/calllog/CallLogFragmentTest.java b/tests/src/com/android/contacts/calllog/CallLogFragmentTest.java
index 9cac8fe..89c0a99 100644
--- a/tests/src/com/android/contacts/calllog/CallLogFragmentTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogFragmentTest.java
@@ -619,14 +619,14 @@
 
     /** Asserts that the number and label text view contains the given text. */
     private void assertNumberAndLabelAre(CallLogListItemViews views, CharSequence number,
-            CharSequence numberLabel) {
+            CharSequence label) {
         assertEquals(View.VISIBLE, views.phoneCallDetailsViews.numberView.getVisibility());
-        final CharSequence expectedText;
-        if (numberLabel == null) {
-            expectedText = number;
-        } else {
-            expectedText = numberLabel + " " + number;
+        assertEquals(number, views.phoneCallDetailsViews.numberView.getText().toString());
+
+        assertEquals(label == null ? View.GONE : View.VISIBLE,
+                views.phoneCallDetailsViews.labelView.getVisibility());
+        if (label != null) {
+            assertEquals(label, views.phoneCallDetailsViews.labelView.getText().toString());
         }
-        assertEquals(expectedText, views.phoneCallDetailsViews.numberView.getText().toString());
     }
 }
diff --git a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
index 19b14d9..131af96 100644
--- a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
+++ b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
@@ -21,6 +21,7 @@
 import com.google.common.collect.Lists;
 
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 
 import java.util.ArrayList;
@@ -33,6 +34,7 @@
 /**
  * Unit tests for {@link StreamItemAdapter}.
  */
+@SmallTest
 public class StreamItemAdapterTest extends AndroidTestCase {
     private StreamItemAdapter mAdapter;
     private FakeOnClickListener mListener;
diff --git a/tests/src/com/android/contacts/format/PrefixHighligherTest.java b/tests/src/com/android/contacts/format/PrefixHighligherTest.java
index a0c0ff3..668330b 100644
--- a/tests/src/com/android/contacts/format/PrefixHighligherTest.java
+++ b/tests/src/com/android/contacts/format/PrefixHighligherTest.java
@@ -17,11 +17,13 @@
 package com.android.contacts.format;
 
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.TextView;
 
 /**
  * Unit tests for {@link PrefixHighlighter}.
  */
+@SmallTest
 public class PrefixHighligherTest extends AndroidTestCase {
     private static final int TEST_PREFIX_HIGHLIGHT_COLOR = 0xFF0000;
     /** The HTML code used to mark the start of the highlighted part. */
diff --git a/tests/src/com/android/contacts/format/SpannedTestUtils.java b/tests/src/com/android/contacts/format/SpannedTestUtils.java
index 625c6aa..646a7ec 100644
--- a/tests/src/com/android/contacts/format/SpannedTestUtils.java
+++ b/tests/src/com/android/contacts/format/SpannedTestUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.format;
 
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.Html;
 import android.text.Spanned;
 import android.text.TextUtils;
@@ -26,6 +27,7 @@
 /**
  * Utility class to check the value of spanned text in text views.
  */
+@SmallTest
 public class SpannedTestUtils {
     /**
      * Checks that the text contained in the text view matches the given HTML text.
diff --git a/tests/src/com/android/contacts/format/TestTextWithHighlightingFactory.java b/tests/src/com/android/contacts/format/TestTextWithHighlightingFactory.java
index f2848d0..2deaef3 100644
--- a/tests/src/com/android/contacts/format/TestTextWithHighlightingFactory.java
+++ b/tests/src/com/android/contacts/format/TestTextWithHighlightingFactory.java
@@ -21,10 +21,12 @@
 
 import android.database.CharArrayBuffer;
 import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableStringBuilder;
 import android.text.style.StyleSpan;
 
 /** A factory for {@link TextWithHighlighting} that wraps its parts in italics. */
+@SmallTest
 public final class TestTextWithHighlightingFactory implements TextWithHighlightingFactory {
     /** A {@link TextWithHighlighting} implementation that wraps its parts in italics. */
     private final static class TestTextWithHighlighting extends SpannableStringBuilder
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index 2c4b74c..b37d24f 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -35,7 +35,7 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Contacts.Entity;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.Smoke;
+import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Tests for {@link ContactDeletionInteraction}.
@@ -47,7 +47,7 @@
  *   adb shell am instrument \
  *     -w com.android.contacts.tests/android.test.InstrumentationTestRunner
  */
-@Smoke
+@SmallTest
 public class ContactDeletionInteractionTest
         extends ActivityInstrumentationTestCase2<FragmentTestActivity> {
 
diff --git a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
index e0b443a..9490b1b 100644
--- a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
@@ -29,11 +29,12 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.Smoke;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -48,7 +49,7 @@
  *   adb shell am instrument \
  *     -w com.android.contacts.tests/android.test.InstrumentationTestRunner
  */
-@Smoke
+@SmallTest
 public class PhoneNumberInteractionTest extends InstrumentationTestCase {
 
     static {
@@ -89,7 +90,8 @@
     public void testSendSmsWhenOnlyOneNumberAvailable() {
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
         expectQuery(contactUri)
-                .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null);
+                .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null,
+                        Phone.CONTENT_ITEM_TYPE);
 
         TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
                 mContext, InteractionType.SMS, null);
@@ -107,7 +109,8 @@
     public void testSendSmsWhenDataIdIsProvided() {
         Uri dataUri = ContentUris.withAppendedId(Data.CONTENT_URI, 1);
         expectQuery(dataUri, true /* isDataUri */ )
-                .returnRow(1, "987", 0, null, null, Phone.TYPE_HOME, null);
+                .returnRow(1, "987", 0, null, null, Phone.TYPE_HOME, null,
+                        Phone.CONTENT_ITEM_TYPE);
 
         TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
                 mContext, InteractionType.SMS, null);
@@ -125,8 +128,10 @@
     public void testSendSmsWhenThereIsPrimaryNumber() {
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
         expectQuery(contactUri)
-                .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null)
-                .returnRow(2, "456", 1, null, null, Phone.TYPE_HOME, null);
+                .returnRow(
+                        1, "123", 0, null, null, Phone.TYPE_HOME, null, Phone.CONTENT_ITEM_TYPE)
+                .returnRow(
+                        2, "456", 1, null, null, Phone.TYPE_HOME, null, Phone.CONTENT_ITEM_TYPE);
 
         TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
                 mContext, InteractionType.SMS, null);
@@ -164,8 +169,10 @@
     public void testCallNumberWhenThereAreDuplicates() {
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
         expectQuery(contactUri)
-                .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null)
-                .returnRow(2, "123", 0, null, null, Phone.TYPE_WORK, null);
+                .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null,
+                        Phone.CONTENT_ITEM_TYPE)
+                .returnRow(2, "123", 0, null, null, Phone.TYPE_WORK, null,
+                        Phone.CONTENT_ITEM_TYPE);
 
         TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
                 mContext, InteractionType.PHONE_CALL, null);
@@ -180,11 +187,31 @@
         assertEquals("tel:123", intent.getDataString());
     }
 
+    public void testCallWithSip() {
+        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
+        expectQuery(contactUri)
+                .returnRow(1, "example@example.com", 0, null, null, Phone.TYPE_HOME, null,
+                        SipAddress.CONTENT_ITEM_TYPE);
+        TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
+                mContext, InteractionType.PHONE_CALL, null);
+
+        interaction.startInteraction(contactUri);
+        interaction.getLoader().waitForLoader();
+
+        Intent intent = mContext.getIntentForStartActivity();
+        assertNotNull(intent);
+
+        assertEquals(Intent.ACTION_CALL_PRIVILEGED, intent.getAction());
+        assertEquals("tel:example%40example.com", intent.getDataString());
+    }
+
     public void testShowDisambigDialogForCalling() {
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
         expectQuery(contactUri)
-                .returnRow(1, "123", 0, "account", null, Phone.TYPE_HOME, "label")
-                .returnRow(2, "456", 0, null, null, Phone.TYPE_WORK, null);
+                .returnRow(1, "123", 0, "account", null, Phone.TYPE_HOME, "label",
+                        Phone.CONTENT_ITEM_TYPE)
+                .returnRow(2, "456", 0, null, null, Phone.TYPE_WORK, null,
+                        Phone.CONTENT_ITEM_TYPE);
 
         TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
                 mContext, InteractionType.PHONE_CALL, null);
@@ -224,7 +251,9 @@
                         RawContacts.ACCOUNT_TYPE,
                         RawContacts.DATA_SET,
                         Phone.TYPE,
-                        Phone.LABEL)
-                .withSelection("mimetype='vnd.android.cursor.item/phone_v2' AND data1 NOT NULL");
+                        Phone.LABEL,
+                        Phone.MIMETYPE)
+                .withSelection("mimetype IN ('vnd.android.cursor.item/phone_v2',"
+                        + " 'vnd.android.cursor.item/sip_address') AND data1 NOT NULL");
     }
 }