Merge "Fix issues with photo selection on Prime."
diff --git a/src/com/android/contacts/CallContactActivity.java b/src/com/android/contacts/CallContactActivity.java
index b7c472a..793770b 100644
--- a/src/com/android/contacts/CallContactActivity.java
+++ b/src/com/android/contacts/CallContactActivity.java
@@ -18,10 +18,8 @@
 
 import com.android.contacts.interactions.PhoneNumberInteraction;
 
-import android.app.Dialog;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnDismissListener;
-import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
@@ -50,7 +48,7 @@
         if (Contacts.CONTENT_ITEM_TYPE.equals(getContentResolver().getType(contactUri))) {
             PhoneNumberInteraction.startInteractionForPhoneCall(this, contactUri);
         } else {
-            startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, contactUri));
+            startActivity(ContactsUtils.getCallIntent(contactUri));
             finish();
         }
     }
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 6224d19..ac26494 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -332,9 +332,8 @@
                 TelephonyManager tm = (TelephonyManager)
                         getSystemService(Context.TELEPHONY_SERVICE);
                 if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
-                    Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                            Uri.fromParts("tel", mNumber, null));
-                    startActivity(callIntent);
+                    startActivity(ContactsUtils.getCallIntent(
+                            Uri.fromParts("tel", mNumber, null)));
                     return true;
                 }
             }
@@ -389,7 +388,6 @@
                 mPhoneCallDetailsHelper.setCallDetailsHeader(mHeaderTextView, firstDetails);
 
                 // Cache the details about the phone number.
-                final Uri numberCallUri = mPhoneNumberHelper.getCallUri(mNumber);
                 final boolean canPlaceCallsTo = mPhoneNumberHelper.canPlaceCallsTo(mNumber);
                 final boolean isVoicemailNumber = mPhoneNumberHelper.isVoicemailNumber(mNumber);
                 final boolean isSipNumber = mPhoneNumberHelper.isSipNumber(mNumber);
@@ -472,8 +470,8 @@
                     ViewEntry entry = new ViewEntry(
                             getString(R.string.menu_callNumber,
                                     FormatUtils.forceLeftToRight(displayNumber)),
-                            new Intent(Intent.ACTION_CALL_PRIVILEGED, numberCallUri),
-                            getString(R.string.description_call, nameOrNumber));
+                                    ContactsUtils.getCallIntent(mNumber),
+                                    getString(R.string.description_call, nameOrNumber));
 
                     // Only show a label if the number is shown and it is not a SIP address.
                     if (!TextUtils.isEmpty(firstDetails.name)
@@ -773,7 +771,7 @@
     }
 
     public void onMenuEditNumberBeforeCall(MenuItem menuItem) {
-        startActivity(new Intent(Intent.ACTION_DIAL, mPhoneNumberHelper.getCallUri(mNumber)));
+        startActivity(new Intent(Intent.ACTION_DIAL, ContactsUtils.getCallUri(mNumber)));
     }
 
     public void onMenuTrashVoicemail(MenuItem menuItem) {
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index cb19713..f7afd22 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts;
 
+import com.android.contacts.activities.DialtactsActivity;
+import com.android.contacts.calllog.PhoneNumberHelper;
 import com.android.contacts.model.AccountType;
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.AccountWithDataSet;
@@ -30,6 +32,7 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.QuickContact;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.view.View;
@@ -213,6 +216,67 @@
     }
 
     /**
+     * Return Uri with an appropriate scheme, accepting Voicemail, SIP, and usual phone call
+     * numbers.
+     */
+    public static Uri getCallUri(String number) {
+        if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+            return Uri.parse("voicemail:");
+        }
+        if (PhoneNumberUtils.isUriNumber(number)) {
+             return Uri.fromParts("sip", number, null);
+        }
+        return Uri.fromParts("tel", number, null);
+     }
+
+    /**
+     * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
+     * automatically.
+     */
+    public static Intent getCallIntent(String number) {
+        return getCallIntent(number, null);
+    }
+
+    /**
+     * Return an Intent for making a phone call. A given Uri will be used as is (without any
+     * sanity check).
+     */
+    public static Intent getCallIntent(Uri uri) {
+        return getCallIntent(uri, null);
+    }
+
+    /**
+     * A variant of {@link #getCallIntent(String)} but also accept a call origin. For more
+     * information about call origin, see comments in Phone package (PhoneApp).
+     */
+    public static Intent getCallIntent(String number, String callOrigin) {
+        return getCallIntent(getCallUri(number), callOrigin);
+    }
+
+    /**
+     * A variant of {@link #getCallIntent(Uri)} but also accept a call origin. For more
+     * information about call origin, see comments in Phone package (PhoneApp).
+     */
+    public static Intent getCallIntent(Uri uri, String callOrigin) {
+        final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (callOrigin != null) {
+            intent.putExtra(DialtactsActivity.EXTRA_CALL_ORIGIN, callOrigin);
+        }
+        return intent;
+    }
+
+    /**
+     * Return an Intent for launching voicemail screen.
+     */
+    public static Intent getVoicemailIntent() {
+        final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+                Uri.fromParts("voicemail", "", null));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return intent;
+    }
+
+    /**
      * Returns a header view based on the R.layout.list_separator, where the
      * containing {@link TextView} is set using the given textResourceId.
      */
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index d4a96e1..37875b0 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -111,14 +111,6 @@
 
     private static final int SUBACTIVITY_ACCOUNT_FILTER = 1;
 
-    /**
-     * Listener interface for Fragments accommodated in {@link ViewPager} enabling them to know
-     * when it becomes visible or invisible inside the ViewPager.
-     */
-    public interface ViewPagerVisibilityListener {
-        public void onVisibilityChanged(boolean visible);
-    }
-
     public class ViewPagerAdapter extends FragmentPagerAdapter {
         public ViewPagerAdapter(FragmentManager fm) {
             super(fm);
@@ -185,7 +177,7 @@
             //   the page migration being completed.
             // - We should delay the method for the call log screen. The screen will update
             //   its internal state and may query full call log. which is too costly to do when
-            //   onVisibilityChanged() is called, making the animation slower.
+            //   setMenuVisibility() is called, making the animation slower.
             // - We should *not* delay the method for the phone favorite screen. The screen has
             //   another icon the call log screen doesn't have. We want to show/hide it immediately
             //   after user's choosing pages.
@@ -551,14 +543,8 @@
         if (fragment instanceof DialpadFragment) {
             mDialpadFragment = (DialpadFragment) fragment;
             mDialpadFragment.setListener(mDialpadListener);
-            if (currentPosition == TAB_INDEX_DIALER) {
-                mDialpadFragment.onVisibilityChanged(true);
-            }
         } else if (fragment instanceof CallLogFragment) {
             mCallLogFragment = (CallLogFragment) fragment;
-            if (currentPosition == TAB_INDEX_CALL_LOG) {
-                mCallLogFragment.onVisibilityChanged(true);
-            }
         } else if (fragment instanceof PhoneFavoriteFragment) {
             mPhoneFavoriteFragment = (PhoneFavoriteFragment) fragment;
             mPhoneFavoriteFragment.setListener(mPhoneFavoriteListener);
@@ -566,9 +552,6 @@
                     && 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);
@@ -1002,8 +985,8 @@
         // Position can be -1 initially. See PageChangeListener.
         if (position >= 0) {
             final Fragment fragment = getFragmentAt(position);
-            if (fragment instanceof ViewPagerVisibilityListener) {
-                ((ViewPagerVisibilityListener) fragment).onVisibilityChanged(visibility);
+            if (fragment != null) {
+                fragment.setMenuVisibility(visibility);
             }
         }
     }
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 40fa5bc..9e52b4f 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -19,7 +19,6 @@
 import com.android.common.io.MoreCloseables;
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
-import com.android.contacts.activities.DialtactsActivity.ViewPagerVisibilityListener;
 import com.android.contacts.util.EmptyLoader;
 import com.android.contacts.voicemail.VoicemailStatusHelper;
 import com.android.contacts.voicemail.VoicemailStatusHelper.StatusMessage;
@@ -56,8 +55,8 @@
 /**
  * Displays a list of call log entries.
  */
-public class CallLogFragment extends ListFragment implements ViewPagerVisibilityListener,
-        CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher {
+public class CallLogFragment extends ListFragment
+        implements CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher {
     private static final String TAG = "CallLogFragment";
 
     /**
@@ -69,7 +68,6 @@
     private CallLogQueryHandler mCallLogQueryHandler;
     private boolean mScrollToTop;
 
-    private boolean mShowOptionsMenu;
     /** Whether there is at least one voicemail source installed. */
     private boolean mVoicemailSourcesAvailable = false;
     /** Whether we are currently filtering over voicemail. */
@@ -265,24 +263,20 @@
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-        if (mShowOptionsMenu) {
-            inflater.inflate(R.menu.call_log_options, menu);
-        }
+        inflater.inflate(R.menu.call_log_options, menu);
     }
 
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
-        if (mShowOptionsMenu) {
-            final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all);
-            // Check if all the menu items are inflated correctly. As a shortcut, we assume all
-            // menu items are ready if the first item is non-null.
-            if (itemDeleteAll != null) {
-                itemDeleteAll.setEnabled(mAdapter != null && !mAdapter.isEmpty());
-                menu.findItem(R.id.show_voicemails_only).setVisible(
-                        mVoicemailSourcesAvailable && !mShowingVoicemailOnly);
-                menu.findItem(R.id.show_all_calls).setVisible(
-                        mVoicemailSourcesAvailable && mShowingVoicemailOnly);
-            }
+        final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all);
+        // Check if all the menu items are inflated correctly. As a shortcut, we assume all
+        // menu items are ready if the first item is non-null.
+        if (itemDeleteAll != null) {
+            itemDeleteAll.setEnabled(mAdapter != null && !mAdapter.isEmpty());
+            menu.findItem(R.id.show_voicemails_only).setVisible(
+                    mVoicemailSourcesAvailable && !mShowingVoicemailOnly);
+            menu.findItem(R.id.show_all_calls).setVisible(
+                    mVoicemailSourcesAvailable && mShowingVoicemailOnly);
         }
     }
 
@@ -329,8 +323,7 @@
             Intent intent;
             // If "number" is really a SIP address, construct a sip: URI.
             if (PhoneNumberUtils.isUriNumber(number)) {
-                intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                                    Uri.fromParts("sip", number, null));
+                intent = ContactsUtils.getCallIntent(Uri.fromParts("sip", number, null));
             } else {
                 // We're calling a regular PSTN phone number.
                 // Construct a tel: URI, but do some other possible cleanup first.
@@ -342,8 +335,7 @@
                     String countryIso = cursor.getString(CallLogQuery.COUNTRY_ISO);
                     number = mAdapter.getBetterNumberFromContacts(number, countryIso);
                 }
-                intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                                    Uri.fromParts("tel", number, null));
+                intent = ContactsUtils.getCallIntent(Uri.fromParts("tel", number, null));
             }
             intent.setFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -357,16 +349,13 @@
     }
 
     @Override
-    public void onVisibilityChanged(boolean visible) {
-        if (mShowOptionsMenu != visible) {
-            mShowOptionsMenu = visible;
-        }
-
-        if (visible && isResumed()) {
+    public void setMenuVisibility(boolean menuVisible) {
+        super.setMenuVisibility(menuVisible);
+        if (menuVisible && isResumed()) {
             refreshData();
         }
 
-        if (!visible) {
+        if (!menuVisible) {
             updateOnExit();
         }
     }
@@ -410,7 +399,8 @@
     private void updateOnTransition(boolean onEntry) {
         // We don't want to update any call data when keyguard is on because the user has likely not
         // seen the new calls yet.
-        if (!mKeyguardManager.inKeyguardRestrictedInputMode()) {
+        // This might be called before onCreate() and thus we need to check null explicitly.
+        if (mKeyguardManager != null && !mKeyguardManager.inKeyguardRestrictedInputMode()) {
             // On either of the transitions we reset the new flag and update the notifications.
             // While exiting we additionally consume all missed calls (by marking them as read).
             // This will ensure that they no more appear in the "new" section when we return back.
diff --git a/src/com/android/contacts/calllog/CallLogListItemHelper.java b/src/com/android/contacts/calllog/CallLogListItemHelper.java
index bfedba5..9485b54 100644
--- a/src/com/android/contacts/calllog/CallLogListItemHelper.java
+++ b/src/com/android/contacts/calllog/CallLogListItemHelper.java
@@ -45,7 +45,7 @@
     public CallLogListItemHelper(PhoneCallDetailsHelper phoneCallDetailsHelper,
             PhoneNumberHelper phoneNumberHelper, Resources resources) {
         mPhoneCallDetailsHelper = phoneCallDetailsHelper;
-        mPhoneNumberHelper= phoneNumberHelper;
+        mPhoneNumberHelper = phoneNumberHelper;
         mResources = resources;
     }
 
diff --git a/src/com/android/contacts/calllog/IntentProvider.java b/src/com/android/contacts/calllog/IntentProvider.java
index bfee5ec..7ddfecc 100644
--- a/src/com/android/contacts/calllog/IntentProvider.java
+++ b/src/com/android/contacts/calllog/IntentProvider.java
@@ -17,6 +17,7 @@
 package com.android.contacts.calllog;
 
 import com.android.contacts.CallDetailActivity;
+import com.android.contacts.ContactsUtils;
 
 import android.content.ContentUris;
 import android.content.Context;
@@ -38,16 +39,7 @@
         return new IntentProvider() {
             @Override
             public Intent getIntent(Context context) {
-                // Here, "number" can either be a PSTN phone number or a
-                // SIP address.  So turn it into either a tel: URI or a
-                // sip: URI, as appropriate.
-                Uri uri;
-                if (PhoneNumberUtils.isUriNumber(number)) {
-                    uri = Uri.fromParts("sip", number, null);
-                } else {
-                    uri = Uri.fromParts("tel", number, null);
-                }
-                return new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
+                return ContactsUtils.getCallIntent(number);
             }
         };
     }
diff --git a/src/com/android/contacts/calllog/PhoneNumberHelper.java b/src/com/android/contacts/calllog/PhoneNumberHelper.java
index 20031b2..af7c2f6 100644
--- a/src/com/android/contacts/calllog/PhoneNumberHelper.java
+++ b/src/com/android/contacts/calllog/PhoneNumberHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.calllog;
 
+import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
 import com.android.internal.telephony.CallerInfo;
 
@@ -76,23 +77,18 @@
         }
     }
 
-    /** Returns a URI that can be used to place a call to this number. */
-    public Uri getCallUri(String number) {
-        if (isVoicemailNumber(number)) {
-            return Uri.parse("voicemail:x");
-        }
-        if (isSipNumber(number)) {
-             return Uri.fromParts("sip", number, null);
-        }
-         return Uri.fromParts("tel", number, null);
-     }
-
-    /** Returns true if the given number is the number of the configured voicemail. */
+    /**
+     * Returns true if the given number is the number of the configured voicemail.
+     * To be able to mock-out this, it is not a static method.
+     */
     public boolean isVoicemailNumber(CharSequence number) {
         return PhoneNumberUtils.isVoiceMailNumber(number.toString());
     }
 
-    /** Returns true if the given number is a SIP address. */
+    /**
+     * Returns true if the given number is a SIP address.
+     * To be able to mock-out this, it is not a static method.
+     */
     public boolean isSipNumber(CharSequence number) {
         return PhoneNumberUtils.isUriNumber(number.toString());
     }
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 84e1d0c..a5bea92 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -609,8 +609,8 @@
                             entryValues.getAsString(PhoneLookup.NORMALIZED_NUMBER);
                     entry.data = PhoneNumberUtils.formatNumber(
                             entry.data, phoneNumberE164, mDefaultCountryIso);
-                    final Intent phoneIntent = mHasPhone ? new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                            Uri.fromParts(Constants.SCHEME_TEL, entry.data, null)) : null;
+                    final Intent phoneIntent = mHasPhone ?
+                            ContactsUtils.getCallIntent(entry.data) : null;
                     final Intent smsIntent = mHasSms ? new Intent(Intent.ACTION_SENDTO,
                             Uri.fromParts(Constants.SCHEME_SMSTO, entry.data, null)) : null;
 
@@ -706,7 +706,7 @@
                     entry.uri = null;
                     entry.maxLines = SIP_ADDRESS_MAX_LINES;
                     if (mHasSip) {
-                        entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+                        entry.intent = ContactsUtils.getCallIntent(
                                 Uri.fromParts(Constants.SCHEME_SIP, entry.data, null));
                     } else {
                         entry.intent = null;
@@ -1937,9 +1937,7 @@
                     }
                 } else if (mPrimaryPhoneUri != null) {
                     // There isn't anything selected, call the default number
-                    final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                            mPrimaryPhoneUri);
-                    mContext.startActivity(intent);
+                    mContext.startActivity(ContactsUtils.getCallIntent(mPrimaryPhoneUri));
                     return true;
                 }
                 return false;
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index 41f713d..bf2a5bc 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -20,7 +20,6 @@
 import com.android.contacts.R;
 import com.android.contacts.SpecialCharSequenceMgr;
 import com.android.contacts.activities.DialtactsActivity;
-import com.android.contacts.activities.DialtactsActivity.ViewPagerVisibilityListener;
 import com.android.contacts.util.PhoneNumberFormatter;
 import com.android.internal.telephony.ITelephony;
 import com.android.phone.CallLogAsync;
@@ -83,8 +82,7 @@
         implements View.OnClickListener,
         View.OnLongClickListener, View.OnKeyListener,
         AdapterView.OnItemClickListener, TextWatcher,
-        PopupMenu.OnMenuItemClickListener,
-        ViewPagerVisibilityListener {
+        PopupMenu.OnMenuItemClickListener {
     private static final String TAG = DialpadFragment.class.getSimpleName();
 
     private static final String EMPTY_NUMBER = "";
@@ -127,8 +125,6 @@
      */
     private String mProhibitedPhoneNumberRegexp;
 
-    private boolean mShowOptionsMenu;
-
 
     // Last number dialed, retrieved asynchronously from the call DB
     // in onCreate. This number is displayed when the user hits the
@@ -562,7 +558,7 @@
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-        if (mShowOptionsMenu && ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+        if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
                 isLayoutReady() && mDialpadChooser != null) {
             inflater.inflate(R.menu.dialpad_options, menu);
         }
@@ -571,7 +567,7 @@
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
         // Hardware menu key should be available and Views should already be ready.
-        if (mShowOptionsMenu && ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+        if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
                 isLayoutReady() && mDialpadChooser != null) {
              setupMenuItems(menu);
         }
@@ -829,7 +825,7 @@
     }
 
     public void callVoicemail() {
-        startActivity(newVoicemailIntent());
+        startActivity(ContactsUtils.getVoicemailIntent());
         mDigits.getText().clear(); // TODO: Fix bug 1745781
         getActivity().finish();
     }
@@ -958,11 +954,9 @@
                 // Clear the digits just in case.
                 mDigits.getText().clear();
             } else {
-                final Intent intent = newDialNumberIntent(number);
-                if (getActivity() instanceof DialtactsActivity) {
-                    intent.putExtra(DialtactsActivity.EXTRA_CALL_ORIGIN,
-                            DialtactsActivity.CALL_ORIGIN_DIALTACTS);
-                }
+                final Intent intent = ContactsUtils.getCallIntent(number,
+                        (getActivity() instanceof DialtactsActivity ?
+                                DialtactsActivity.CALL_ORIGIN_DIALTACTS : null));
                 startActivity(intent);
                 mDigits.getText().clear();  // TODO: Fix bug 1745781
                 getActivity().finish();
@@ -1420,33 +1414,13 @@
         mCallLog.getLastOutgoingCall(lastCallArgs);
     }
 
-    // Helpers for the call intents.
-    private Intent newVoicemailIntent() {
-        final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                                         Uri.fromParts("voicemail", EMPTY_NUMBER, null));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return intent;
-    }
-
     private Intent newFlashIntent() {
-        final Intent intent = newDialNumberIntent(EMPTY_NUMBER);
+        final Intent intent = ContactsUtils.getCallIntent(EMPTY_NUMBER);
         intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);
         return intent;
     }
 
-    private Intent newDialNumberIntent(String number) {
-        final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                                         Uri.fromParts("tel", number, null));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return intent;
-    }
-
     public void setListener(Listener listener) {
         mListener = listener;
     }
-
-    @Override
-    public void onVisibilityChanged(boolean visible) {
-        mShowOptionsMenu = visible;
-    }
 }
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 4a5a502..475e172 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -131,7 +131,9 @@
 
     @Override
     public boolean isEmpty() {
-        return TextUtils.isEmpty(mDateView.getText());
+        final EditField editField = getKind().fieldList.get(0);
+        final String column = editField.column;
+        return TextUtils.isEmpty(getEntry().getAsString(column));
     }
 
     @Override
@@ -243,6 +245,7 @@
                 } else {
                     resultString = kind.dateFormatWithYear.format(outCalendar.getTime());
                 }
+
                 onFieldChanged(column, resultString);
                 rebuildDateView();
             }
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index 5627aa5..0919006 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -43,6 +43,7 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -196,6 +197,11 @@
                 PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(mContext, fieldView);
             }
 
+            // Show the "next" button in IME to navigate between text fields
+            // TODO: Still need to properly navigate to/from sections without text fields,
+            // See Bug: 5713510
+            fieldView.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+
             // Read current value from state
             final String column = field.column;
             final String value = entry.getAsString(column);
diff --git a/src/com/android/contacts/interactions/PhoneNumberInteraction.java b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
index 4033c71..401cbb1 100644
--- a/src/com/android/contacts/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
@@ -322,11 +322,7 @@
                         Intent.ACTION_SENDTO, Uri.fromParts("sms", phoneNumber, null));
                 break;
             default:
-                intent = new Intent(
-                        Intent.ACTION_CALL_PRIVILEGED, Uri.fromParts("tel", phoneNumber, null));
-                if (callOrigin != null) {
-                    intent.putExtra(DialtactsActivity.EXTRA_CALL_ORIGIN, callOrigin);
-                }
+                intent = ContactsUtils.getCallIntent(phoneNumber, callOrigin);
                 break;
         }
         context.startActivity(intent);
diff --git a/src/com/android/contacts/list/ContactsIntentResolver.java b/src/com/android/contacts/list/ContactsIntentResolver.java
index 8d14591..0584f5e 100644
--- a/src/com/android/contacts/list/ContactsIntentResolver.java
+++ b/src/com/android/contacts/list/ContactsIntentResolver.java
@@ -18,6 +18,7 @@
 
 import com.android.contacts.CallContactActivity;
 import com.android.contacts.ContactsSearchManager;
+import com.android.contacts.ContactsUtils;
 
 import android.app.Activity;
 import android.app.SearchManager;
@@ -128,9 +129,7 @@
             if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG))) {
                 String query = intent.getStringExtra(SearchManager.QUERY);
                 if (!TextUtils.isEmpty(query)) {
-                    Intent newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                            Uri.fromParts("tel", query, null));
-                    request.setRedirectIntent(newIntent);
+                    request.setRedirectIntent(ContactsUtils.getCallIntent(query));
                 }
             } else {
                 request.setQueryString(intent.getStringExtra(SearchManager.QUERY));
@@ -182,7 +181,7 @@
                 intent.setData(null);
             }
         } else if (Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED.equals(action)) {
-            request.setRedirectIntent(new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData()));
+            request.setRedirectIntent(ContactsUtils.getCallIntent(intent.getData()));
         } else if (Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED.equals(action)) {
             // TODO actually support this in EditContactActivity.
             String number = intent.getData().getSchemeSpecificPart();
diff --git a/src/com/android/contacts/list/PhoneFavoriteFragment.java b/src/com/android/contacts/list/PhoneFavoriteFragment.java
index 9e80abd..0e92bfc 100644
--- a/src/com/android/contacts/list/PhoneFavoriteFragment.java
+++ b/src/com/android/contacts/list/PhoneFavoriteFragment.java
@@ -18,7 +18,6 @@
 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;
@@ -35,7 +34,6 @@
 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;
@@ -61,8 +59,7 @@
  * {@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,
-        ViewPagerVisibilityListener{
+public class PhoneFavoriteFragment extends Fragment implements OnItemClickListener {
     private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
     private static final boolean DEBUG = false;
 
@@ -224,8 +221,6 @@
             new ContactsPreferenceChangeListener();
     private final ScrollListener mScrollListener = new ScrollListener();
 
-    private boolean mShowOptionsMenu;
-
     @Override
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
@@ -333,9 +328,7 @@
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-        if (mShowOptionsMenu) {
-            inflater.inflate(R.menu.phone_favorite_options, menu);
-        }
+        inflater.inflate(R.menu.phone_favorite_options, menu);
     }
 
     @Override
@@ -344,7 +337,7 @@
             case R.id.menu_import_export:
                 // We hard-code the "contactsAreAvailable" argument because doing it properly would
                 // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
-                // now in Dialtacts for (potential) performance reasons.  Compare with how it is 
+                // now in Dialtacts for (potential) performance reasons.  Compare with how it is
                 // done in {@link PeopleActivity}.
                 ImportExportDialogFragment.show(getFragmentManager(), true);
                 return true;
@@ -495,9 +488,4 @@
     public void setListener(Listener listener) {
         mListener = listener;
     }
-
-    @Override
-    public void onVisibilityChanged(boolean visible) {
-        mShowOptionsMenu = visible;
-    }
 }
\ No newline at end of file
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index 266fd02..415fa18 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -116,8 +116,8 @@
                 final String number = getAsString(cursor, Phone.NUMBER);
                 if (!TextUtils.isEmpty(number)) {
 
-                    final Intent phoneIntent = hasPhone ? new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                            Uri.fromParts(Constants.SCHEME_TEL, number, null)) : null;
+                    final Intent phoneIntent = hasPhone ? ContactsUtils.getCallIntent(number)
+                            : null;
                     final Intent smsIntent = hasSms ? new Intent(Intent.ACTION_SENDTO,
                             Uri.fromParts(Constants.SCHEME_SMSTO, number, null)) : null;
 
@@ -139,7 +139,7 @@
                 final String address = getAsString(cursor, SipAddress.SIP_ADDRESS);
                 if (!TextUtils.isEmpty(address)) {
                     final Uri callUri = Uri.fromParts(Constants.SCHEME_SIP, address, null);
-                    mIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, callUri);
+                    mIntent = ContactsUtils.getCallIntent(callUri);
                     // Note that this item will get a SIP-specific variant
                     // of the "call phone" icon, rather than the standard
                     // app icon for the Phone app (which we show for
diff --git a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
index 9490b1b..2da8859 100644
--- a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
@@ -202,7 +202,7 @@
         assertNotNull(intent);
 
         assertEquals(Intent.ACTION_CALL_PRIVILEGED, intent.getAction());
-        assertEquals("tel:example%40example.com", intent.getDataString());
+        assertEquals("sip:example%40example.com", intent.getDataString());
     }
 
     public void testShowDisambigDialogForCalling() {
diff --git a/tests/src/com/android/contacts/tests/QueryService.java b/tests/src/com/android/contacts/tests/QueryService.java
index fd349cc..04a95c5 100644
--- a/tests/src/com/android/contacts/tests/QueryService.java
+++ b/tests/src/com/android/contacts/tests/QueryService.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.net.Uri;
+import android.text.TextUtils;
 import android.util.Log;
 
 /**
@@ -28,18 +29,19 @@
  *
    Usage:
      adb shell am startservice -d URI \
-       [-e s OPTIONAL SELECTION] [-e s OPTIONAL ORDER BY]  \
+       [-e p OPTIONAL PROJECTION] [-e s OPTIONAL SELECTION] [-e s OPTIONAL ORDER BY]  \
        com.android.contacts.tests/.QueryService
 
    Example:
 
    adb shell am startservice -d content://com.android.contacts/directories \
-     -e s 'accountName is null' -e o '_id'  \
+     -e p accountName,accountType -e s 'accountName NOT NULL' -e o '_id'  \
      com.android.contacts.tests/.QueryService
  */
 public class QueryService extends IntentService {
     private static final String TAG = "contactsquery";
 
+    private static final String EXTRA_PROJECTION = "p";
     private static final String EXTRA_SELECTION = "s";
     private static final String EXTRA_ORDER = "o";
     private static final String NULL_STRING = "*null*";
@@ -52,39 +54,47 @@
     @Override
     protected void onHandleIntent(Intent intent) {
         final Uri uri = intent.getData();
+        // Unfortunately "am" doesn't support string arrays...
+        final String projection = intent.getStringExtra(EXTRA_PROJECTION);
         final String selection = intent.getStringExtra(EXTRA_SELECTION);
         final String order = intent.getStringExtra(EXTRA_ORDER);
 
         Log.i(TAG, "URI: " + uri);
+        Log.i(TAG, "Projection: " + projection);
         Log.i(TAG, "Selection: " + selection);
 
-        Cursor c = getContentResolver().query(uri, null, selection, null, order);
-        if (c == null) {
-            Log.i(TAG, "(no results)");
-            return;
-        }
-        StringBuilder sb = new StringBuilder();
         try {
-            Log.i(TAG, "Result count: " + c.getCount());
-
-            final int columnCount = c.getColumnCount();
-
-            sb.setLength(0);
-            for (int i = 0; i < columnCount; i++) {
-                add(sb, c.getColumnName(i));
+            Cursor c = getContentResolver().query(uri, parseProjection(projection), selection, null,
+                    order);
+            if (c == null) {
+                Log.i(TAG, "(no results)");
+                return;
             }
-            Log.i(TAG, sb.toString());
+            StringBuilder sb = new StringBuilder();
+            try {
+                Log.i(TAG, "Result count: " + c.getCount());
 
-            c.moveToPosition(-1);
-            while (c.moveToNext()) {
+                final int columnCount = c.getColumnCount();
+
                 sb.setLength(0);
                 for (int i = 0; i < columnCount; i++) {
-                    add(sb, c.getString(i));
+                    add(sb, c.getColumnName(i));
                 }
                 Log.i(TAG, sb.toString());
+
+                c.moveToPosition(-1);
+                while (c.moveToNext()) {
+                    sb.setLength(0);
+                    for (int i = 0; i < columnCount; i++) {
+                        add(sb, c.getString(i));
+                    }
+                    Log.i(TAG, sb.toString());
+                }
+            } finally {
+                c.close();
             }
-        } finally {
-            c.close();
+        } catch (Exception e) {
+            Log.e(TAG, "Exeption while executing query", e);
         }
     }
 
@@ -95,4 +105,15 @@
         sb.append(s == null ? NULL_STRING : s);
         return sb;
     }
+
+    private static String[] parseProjection(String projectionString) {
+        if (TextUtils.isEmpty(projectionString)) {
+            return null; // all columns
+        }
+        final String[] columns = projectionString.split(",");
+        if (columns.length == 0) {
+            return null; // all columns
+        }
+        return columns;
+    }
 }