Bringing Call button back to Strequent view

Change-Id: I5281f6aa3d866a514b918b2add8eff6caa4b0762
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 8a52786..e0b5f98 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts;
 
+import com.android.contacts.list.CallOrSmsInitiator;
 import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
 import com.android.contacts.list.ContactEntryListAdapter;
 import com.android.contacts.list.ContactEntryListFragment;
@@ -436,6 +437,8 @@
 
     private ListView mListView;
 
+    protected CallOrSmsInitiator mCallOrSmsInitiator;
+
     public ContactsListActivity() {
         mIntentResolver = new ContactsIntentResolver(this, this);
     }
@@ -567,11 +570,11 @@
                     }
 
                     public void onCallContactAction(Uri contactUri) {
-                        // TODO
+                        getCallOrSmsInitiator().initiateCall(contactUri);
                     }
 
                     public void onSmsContactAction(Uri contactUri) {
-                        // TODO
+                        getCallOrSmsInitiator().initiateSms(contactUri);
                     }
 
                     public void onDeleteContactAction(Uri contactUri) {
@@ -629,11 +632,11 @@
                     }
 
                     public void onCallContactAction(Uri contactUri) {
-                        // TODO
+                        getCallOrSmsInitiator().initiateCall(contactUri);
                     }
 
                     public void onSmsContactAction(Uri contactUri) {
-                        // TODO
+                        getCallOrSmsInitiator().initiateSms(contactUri);
                     }
 
                     public void onDeleteContactAction(Uri contactUri) {
@@ -2351,4 +2354,11 @@
         // TODO make this triggered by the Loader
         mListFragment.completeRestoreInstanceState();
     }
+
+    private CallOrSmsInitiator getCallOrSmsInitiator() {
+        if (mCallOrSmsInitiator == null) {
+            mCallOrSmsInitiator = new CallOrSmsInitiator(this);
+        }
+        return mCallOrSmsInitiator;
+    }
 }
diff --git a/src/com/android/contacts/PhoneDisambigDialog.java b/src/com/android/contacts/PhoneDisambigDialog.java
index d8cb14e..391ded0 100644
--- a/src/com/android/contacts/PhoneDisambigDialog.java
+++ b/src/com/android/contacts/PhoneDisambigDialog.java
@@ -49,13 +49,12 @@
  * one will be chosen to make a call or initiate an sms message.
  */
 public class PhoneDisambigDialog implements DialogInterface.OnClickListener,
-        DialogInterface.OnDismissListener, CompoundButton.OnCheckedChangeListener{
+        CompoundButton.OnCheckedChangeListener{
 
     private boolean mMakePrimary = false;
     private Context mContext;
     private AlertDialog mDialog;
     private boolean mSendSms;
-    private Cursor mPhonesCursor;
     private ListAdapter mPhonesAdapter;
     private ArrayList<PhoneItem> mPhoneItemList;
 
@@ -66,9 +65,9 @@
     public PhoneDisambigDialog(Context context, Cursor phonesCursor, boolean sendSms) {
         mContext = context;
         mSendSms = sendSms;
-        mPhonesCursor = phonesCursor;
-
         mPhoneItemList = makePhoneItemsList(phonesCursor);
+        phonesCursor.close();
+
         Collapser.collapseList(mPhoneItemList);
 
         mPhonesAdapter = new PhonesAdapter(mContext, mPhoneItemList, mSendSms);
@@ -129,10 +128,6 @@
         mMakePrimary = isChecked;
     }
 
-    public void onDismiss(DialogInterface dialog) {
-        mPhonesCursor.close();
-    }
-
     private static class PhonesAdapter extends ArrayAdapter<PhoneItem> {
         private final boolean sendSms;
         private final Sources mSources;
diff --git a/src/com/android/contacts/list/CallOrSmsInitiator.java b/src/com/android/contacts/list/CallOrSmsInitiator.java
new file mode 100644
index 0000000..1511931
--- /dev/null
+++ b/src/com/android/contacts/list/CallOrSmsInitiator.java
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+package com.android.contacts.list;
+
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.PhoneDisambigDialog;
+
+import android.content.AsyncQueryHandler;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts.Data;
+
+/**
+ * Initiates phone calls or SMS messages.
+ */
+public class CallOrSmsInitiator {
+
+    private final Context mContext;
+    private AsyncQueryHandler mQueryHandler;
+    private int mCurrentToken;
+    private boolean mSendSms;
+
+    private static final String[] PHONE_NUMBER_PROJECTION = new String[] {
+            Phone._ID,
+            Phone.NUMBER,
+            Phone.IS_SUPER_PRIMARY,
+            RawContacts.ACCOUNT_TYPE,
+            Phone.TYPE,
+            Phone.LABEL
+    };
+
+    private static final String PHONE_NUMBER_SELECTION = Data.MIMETYPE + "='"
+            + Phone.CONTENT_ITEM_TYPE + "' AND " + Phone.NUMBER + " NOT NULL";
+
+    public CallOrSmsInitiator(Context context) {
+        this.mContext = context;
+        mQueryHandler = new AsyncQueryHandler(context.getContentResolver()) {
+            @Override
+            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+                onPhoneNumberQueryComplete(token, cookie, cursor);
+            }
+        };
+    }
+
+    protected void onPhoneNumberQueryComplete(int token, Object cookie, Cursor cursor) {
+        if (cursor == null || cursor.getCount() == 0) {
+            cursor.close();
+            return;
+        }
+
+        if (token != mCurrentToken) { // Stale query, ignore
+            cursor.close();
+            return;
+        }
+
+        String phone = null;
+        if (cursor.getCount() == 1) {
+            // only one number, call it.
+            cursor.moveToFirst();
+            phone = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
+        } else {
+            cursor.moveToPosition(-1);
+            while (cursor.moveToNext()) {
+                if (cursor.getInt(cursor.getColumnIndex(Phone.IS_SUPER_PRIMARY)) != 0) {
+                    // Found super primary, call it.
+                    phone = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
+                    break;
+                }
+            }
+        }
+
+        if (phone == null) {
+            // Display dialog to choose a number to call.
+            PhoneDisambigDialog phoneDialog = new PhoneDisambigDialog(mContext, cursor, mSendSms);
+            phoneDialog.show();
+        } else {
+            if (mSendSms) {
+                ContactsUtils.initiateSms(mContext, phone);
+            } else {
+                ContactsUtils.initiateCall(mContext, phone);
+            }
+        }
+    }
+
+    /**
+     * Initiates a phone call with the specified contact. If necessary, displays
+     * a disambiguation dialog to see which number to call.
+     */
+    public void initiateCall(Uri contactUri) {
+        callOrSendSms(contactUri, false);
+    }
+
+    /**
+     * Initiates a text message to the specified contact. If necessary, displays
+     * a disambiguation dialog to see which number to call.
+     */
+    public void initiateSms(Uri contactUri) {
+        callOrSendSms(contactUri, true);
+    }
+
+    private void callOrSendSms(Uri contactUri, boolean sendSms) {
+        mCurrentToken++;
+        mSendSms = sendSms;
+        Uri dataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY);
+        mQueryHandler.startQuery(mCurrentToken, dataUri, dataUri, PHONE_NUMBER_PROJECTION,
+                PHONE_NUMBER_SELECTION, null, null);
+    }
+}
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index 1d7f72f..1b6e444 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -24,7 +24,6 @@
 import android.provider.ContactsContract.SearchSnippetColumns;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.QuickContactBadge;
 
@@ -144,71 +143,61 @@
         final ContactListItemView view = new ContactListItemView(context, null);
         view.setUnknownNameText(mUnknownNameText);
         view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
-        // TODO
-//        view.setOnCallButtonClickListener(contactsListActivity);
         return view;
     }
 
-    @Override
-    public void bindView(View itemView, Context context, Cursor cursor) {
-        final ContactListItemView view = (ContactListItemView)itemView;
-
-        if (isSectionHeaderDisplayEnabled()) {
-            final int position = cursor.getPosition();
-            final int section = getSectionForPosition(position);
-            if (getPositionForSection(section) == position) {
-                String title = (String)getSections()[section];
-                view.setSectionHeader(title);
-            } else {
-                view.setDividerVisible(false);
-                view.setSectionHeader(null);
-            }
-
-            // move the divider for the last item in a section
-            if (getPositionForSection(section + 1) - 1 == position) {
-                view.setDividerVisible(false);
-            } else {
-                view.setDividerVisible(true);
-            }
+    protected void bindSectionHeaderAndDivider(final ContactListItemView view, Cursor cursor) {
+        final int position = cursor.getPosition();
+        final int section = getSectionForPosition(position);
+        if (getPositionForSection(section) == position) {
+            String title = (String)getSections()[section];
+            view.setSectionHeader(title);
+        } else {
+            view.setDividerVisible(false);
+            view.setSectionHeader(null);
         }
 
-        view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
-                mAlternativeDisplayNameColumnIndex);
-//
-//        // Make the call button visible if requested.
-//        if (mDisplayCallButton
-//                && cursor.getColumnCount() > ContactsListActivity.SUMMARY_HAS_PHONE_COLUMN_INDEX
-//                && cursor.getInt(ContactsListActivity.SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0) {
-//            int pos = cursor.getPosition();
-//            view.showCallButton(android.R.id.button1, pos);
-//        } else {
-//            view.hideCallButton();
-//        }
-//
+        // move the divider for the last item in a section
+        if (getPositionForSection(section + 1) - 1 == position) {
+            view.setDividerVisible(false);
+        } else {
+            view.setDividerVisible(true);
+        }
+    }
 
+    protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
         // Set the photo, if available
         long photoId = 0;
         if (!cursor.isNull(SUMMARY_PHOTO_ID_COLUMN_INDEX)) {
             photoId = cursor.getLong(SUMMARY_PHOTO_ID_COLUMN_INDEX);
         }
 
-        ImageView viewToUse;
-        if (mQuickContactEnabled) {
-            QuickContactBadge quickContact = view.getQuickContact();
-            quickContact.assignContactUri(getContactUri());
-            viewToUse = quickContact;
-        } else {
-            viewToUse = view.getPhotoView();
+        getPhotoLoader().loadPhoto(view.getPhotoView(), photoId);
+    }
+
+    protected void bindQuickContact(final ContactListItemView view, Cursor cursor) {
+        long photoId = 0;
+        if (!cursor.isNull(SUMMARY_PHOTO_ID_COLUMN_INDEX)) {
+            photoId = cursor.getLong(SUMMARY_PHOTO_ID_COLUMN_INDEX);
         }
 
-        getPhotoLoader().loadPhoto(viewToUse, photoId);
+        QuickContactBadge quickContact = view.getQuickContact();
+        quickContact.assignContactUri(getContactUri());
+        getPhotoLoader().loadPhoto(quickContact, photoId);
+    }
 
-        view.showPresence(cursor, SUMMARY_PRESENCE_STATUS_COLUMN_INDEX);
+    protected void bindName(final ContactListItemView view, Cursor cursor) {
+        view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
+                mAlternativeDisplayNameColumnIndex);
         view.showPhoneticName(cursor, SUMMARY_PHONETIC_NAME_COLUMN_INDEX);
+    }
 
-        if (isSearchMode() || isSearchResultsMode()) {
-            view.showSnippet(cursor, SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX,
-                    SUMMARY_SNIPPET_DATA1_COLUMN_INDEX, SUMMARY_SNIPPET_DATA4_COLUMN_INDEX);
-        }
+    protected void bindPresence(final ContactListItemView view, Cursor cursor) {
+        view.showPresence(cursor, SUMMARY_PRESENCE_STATUS_COLUMN_INDEX);
+    }
+
+    protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
+        view.showSnippet(cursor, SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX,
+                SUMMARY_SNIPPET_DATA1_COLUMN_INDEX, SUMMARY_SNIPPET_DATA4_COLUMN_INDEX);
     }
 }
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index ef131d1..23e31a0 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -223,7 +223,12 @@
             mHeaderTextView.measure(
                     MeasureSpec.makeMeasureSpec(mHeaderTextWidth, MeasureSpec.EXACTLY),
                     MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
-            height += mHeaderBackgroundDrawable.getIntrinsicHeight();
+            height += mHeaderBackgroundHeight;
+        }
+
+        if (mHorizontalDividerVisible) {
+            ensureHorizontalDivider();
+            height += mHorizontalDividerHeight;
         }
 
         setMeasuredDimension(width, height);
@@ -337,7 +342,7 @@
                     rightBound,
                     topBound,
                     rightBound + buttonWidth,
-                    height);
+                    height - mHorizontalDividerHeight);
             mVerticalDividerVisible = true;
             ensureVerticalDivider();
             rightBound -= mVerticalDividerWidth;
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index f310c5c..309475c 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -69,13 +69,20 @@
         final ContactListItemView view = new ContactListItemView(context, null);
         view.setUnknownNameText(getUnknownNameText());
         view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
-        // TODO
-//        view.setOnCallButtonClickListener(contactsListActivity);
         return view;
     }
 
     @Override
     public void bindView(View itemView, Context context, Cursor cursor) {
-        super.bindView(itemView, context, cursor);
+        final ContactListItemView view = (ContactListItemView)itemView;
+
+        bindSectionHeaderAndDivider(view, cursor);
+        bindQuickContact(view, cursor);
+        bindName(view, cursor);
+        bindPresence(view, cursor);
+
+        if (isSearchMode() || isSearchResultsMode()) {
+            bindSearchSnippet(view, cursor);
+        }
     }
 }
diff --git a/src/com/android/contacts/list/StrequentContactListAdapter.java b/src/com/android/contacts/list/StrequentContactListAdapter.java
index dc20c97..8760160 100644
--- a/src/com/android/contacts/list/StrequentContactListAdapter.java
+++ b/src/com/android/contacts/list/StrequentContactListAdapter.java
@@ -25,6 +25,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.View.OnClickListener;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -36,9 +37,16 @@
 
     private int mFrequentSeparatorPos;
     private TextView mSeparatorView;
+    private OnClickListener mCallButtonListener;
+    private int mCallButtonId;
 
-    public StrequentContactListAdapter(Context context) {
+    public StrequentContactListAdapter(Context context, int callButtonId) {
         super(context);
+        mCallButtonId = callButtonId;
+    }
+
+    public void setCallButtonListener(OnClickListener callButtonListener) {
+        mCallButtonListener = callButtonListener;
     }
 
     @Override
@@ -142,13 +150,25 @@
         final ContactListItemView view = new ContactListItemView(context, null);
         view.setUnknownNameText(getUnknownNameText());
         view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
-        // TODO
-//        view.setOnCallButtonClickListener(contactsListActivity);
+        view.setOnCallButtonClickListener(mCallButtonListener);
         return view;
     }
 
     @Override
     public void bindView(View itemView, Context context, Cursor cursor) {
-        super.bindView(itemView, context, cursor);
+        final ContactListItemView view = (ContactListItemView)itemView;
+
+        bindName(view, cursor);
+        bindQuickContact(view, cursor);
+        bindPresence(view, cursor);
+
+        // Make the call button visible if requested.
+        if (getHasPhoneNumber()) {
+            int position = cursor.getPosition();
+            view.showCallButton(mCallButtonId, position);
+        } else {
+            view.hideCallButton();
+        }
+
     }
 }
diff --git a/src/com/android/contacts/list/StrequentContactListFragment.java b/src/com/android/contacts/list/StrequentContactListFragment.java
index fd746ae..fac741b 100644
--- a/src/com/android/contacts/list/StrequentContactListFragment.java
+++ b/src/com/android/contacts/list/StrequentContactListFragment.java
@@ -20,11 +20,15 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.View.OnClickListener;
 
 /**
  * Fragment containing a list of starred contacts followed by a list of frequently contacted.
  */
-public class StrequentContactListFragment extends ContactBrowseListFragment {
+public class StrequentContactListFragment extends ContactBrowseListFragment
+        implements OnClickListener {
+
+    private static final int CALL_BUTTON_ID = android.R.id.button1;
 
     @Override
     protected void onItemClick(int position, long id) {
@@ -35,7 +39,8 @@
 
     @Override
     protected ContactListAdapter createListAdapter() {
-        StrequentContactListAdapter adapter = new StrequentContactListAdapter(getActivity());
+        StrequentContactListAdapter adapter =
+                new StrequentContactListAdapter(getActivity(), CALL_BUTTON_ID);
         adapter.setSectionHeaderDisplayEnabled(false);
 
         adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
@@ -44,6 +49,7 @@
         adapter.setDisplayPhotos(true);
         adapter.setQuickContactEnabled(true);
 
+        adapter.setCallButtonListener(this);
         adapter.configureLoader(getLoader());
         return adapter;
     }
@@ -52,4 +58,17 @@
     protected View inflateView(LayoutInflater inflater, ViewGroup container) {
         return inflater.inflate(R.layout.contacts_list_content, null);
     }
+
+    public void onClick(View v) {
+        int id = v.getId();
+        switch (id) {
+            case CALL_BUTTON_ID: {
+                final int position = (Integer)v.getTag();
+                ContactListAdapter adapter = getAdapter();
+                adapter.moveToPosition(position);
+                callContact(adapter.getContactUri());
+                break;
+            }
+        }
+    }
 }