Merge "Add footer actions to Call Details." into ub-contactsdialer-a-dev
diff --git a/res/layout/call_detail_footer.xml b/res/layout/call_detail_footer.xml
new file mode 100644
index 0000000..7e56c02
--- /dev/null
+++ b/res/layout/call_detail_footer.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/divider_line_thickness"
+        android:background="@color/call_log_action_divider" />
+
+    <LinearLayout android:id="@+id/call_detail_action_block"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:visibility="gone"
+        style="@style/CallDetailActionItemStyle">
+
+        <TextView android:id="@+id/call_detail_action_block_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/action_block_number" />
+
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/call_detail_action_copy"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        style="@style/CallDetailActionItemStyle">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/action_copy_number_text" />
+
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/call_detail_action_edit_before_call"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:visibility="gone"
+        style="@style/CallDetailActionItemStyle">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/action_edit_number_before_call" />
+
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/call_detail_action_report"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:visibility="gone"
+        style="@style/CallDetailActionItemStyle">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/action_report_number" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/res/menu/call_details_cab.xml b/res/menu/call_details_cab.xml
deleted file mode 100644
index 7de675f..0000000
--- a/res/menu/call_details_cab.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/copy_phone_number"
-        android:icon="?android:attr/actionModeCopyDrawable"
-        android:title="@string/menu_copy"
-    />
-</menu>
diff --git a/res/menu/call_details_options.xml b/res/menu/call_details_options.xml
deleted file mode 100644
index 414b671..0000000
--- a/res/menu/call_details_options.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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"
-    android:id="@+id/call_details_menu">
-
-    <item android:id="@+id/menu_edit_number_before_call"
-        android:title="@string/call_log_edit_number_before_call" />
-
-    <item android:id="@+id/menu_report"
-        android:title="@string/call_detail_menu_report" />
-
-</menu>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b38994b..07891f4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,6 +16,7 @@
 -->
 <resources>
     <dimen name="button_horizontal_padding">16dp</dimen>
+    <dimen name="divider_line_thickness">2dp</dimen>
 
     <!--
           Drag to remove view (in dp because it is used in conjunction with a statically
@@ -47,6 +48,8 @@
     <dimen name="call_detail_header_top_margin">20dp</dimen>
     <dimen name="call_detail_header_bottom_margin">9dp</dimen>
     <dimen name="call_detail_elevation">0.5dp</dimen>
+    <dimen name="call_detail_action_item_padding_horizontal">36dp</dimen>
+    <dimen name="call_detail_action_item_padding_vertical">16dp</dimen>
     <dimen name="transcription_top_margin">18dp</dimen>
     <dimen name="transcription_bottom_margin">18dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a4b64a9..cd7ce8f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -42,25 +42,24 @@
     [CHAR LIMIT=NONE] -->
     <string name="callHistoryIconLabel">Call history</string>
 
-    <!-- Text for a menu item to report a call as having been incorrectly identified.
-         [CHAR LIMIT=30] -->
-    <string name="call_detail_menu_report">Report inaccurate number</string>
+    <!-- Text for a menu item to report a call as having been incorrectly identified. [CHAR LIMIT=48] -->
+    <string name="action_report_number">Report inaccurate number</string>
 
-    <!-- Option displayed in context menu to copy long pressed phone number to clipboard [CHAR LIMIT=64] -->
-    <string name="copy_number_text">Copy number to clipboard</string>
+    <!-- Option displayed in context menu to copy long pressed phone number. [CHAR LIMIT=48] -->
+    <string name="action_copy_number_text">Copy number</string>
 
-    <!-- Option displayed in context menu to copy long pressed voicemail transcription to clipboard [CHAR LIMIT=64] -->
-    <string name="copy_transcript_text">Copy transcription to clipboard</string>
+    <!-- Option displayed in context menu to copy long pressed voicemail transcription. [CHAR LIMIT=48] -->
+    <string name="copy_transcript_text">Copy transcription</string>
 
-    <!-- Menu item used to block a number from the call log [CHAR LIMIT=64] -->
-    <string name="call_log_block_number">Block number</string>
+    <!-- Label for action to block a number. [CHAR LIMIT=48] -->
+    <string name="action_block_number">Block number</string>
 
     <!-- Text for snackbar to undo blocking a number. [CHAR LIMIT=64] -->
     <string name="snackbar_number_blocked">
         <xliff:g id="number" example="(555) 555-5555">%1$s</xliff:g> added to block list</string>
 
-    <!-- Menu item used to unblock a number from the call log [CHAR LIMIT=64]-->
-    <string name="call_log_unblock_number">Unblock number</string>
+    <!-- Label for action to unblock a number [CHAR LIMIT=48]-->
+    <string name="action_unblock_number">Unblock number</string>
 
     <!-- Text for snackbar to undo unblocking a number. [CHAR LIMIT=64] -->
     <string name="snackbar_number_unblocked">
@@ -73,11 +72,8 @@
     <!-- Menu item in call details used to remove a call or voicemail from the call log. -->
     <string name="call_details_delete">Delete</string>
 
-    <!-- Menu item used to copy a number from the call log to the dialer so it can be edited before calling it -->
-    <string name="call_log_edit_number_before_call">Edit number before call</string>
-
-    <!-- Menu item used to remove a single call from the call log -->
-    <string name="call_log_remove_from_call_log">Delete from call history</string>
+    <!-- Label for action to edit a number before calling it. [CHAR LIMIT=48] -->
+    <string name="action_edit_number_before_call">Edit number before call</string>
 
     <!-- Menu item used to remove all calls from the call log -->
     <string name="call_log_delete_all">Clear call history</string>
@@ -260,9 +256,6 @@
          [CHAR LIMIT=NONE] -->
     <string name="action_menu_dialpad_button">dial pad</string>
 
-    <!-- Menu item to copy something [CHAR_LIMIT=10] -->
-    <string name="menu_copy">Copy</string>
-
     <!-- Menu item used to show only outgoing in the call log. [CHAR LIMIT=30] -->
     <string name="menu_show_outgoing_only">Show outgoing only</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f21d62f..7c81e52 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -146,6 +146,15 @@
         <item name="android:actionOverflowButtonStyle">@style/DialtactsActionBarOverflowWhite</item>
     </style>
 
+    <style name="CallDetailActionItemStyle">
+        <item name="android:foreground">?android:attr/selectableItemBackground</item>
+        <item name="android:clickable">true</item>
+        <item name="android:paddingStart">@dimen/call_detail_action_item_padding_horizontal</item>
+        <item name="android:paddingEnd">@dimen/call_detail_action_item_padding_horizontal</item>
+        <item name="android:paddingTop">@dimen/call_detail_action_item_padding_vertical</item>
+        <item name="android:paddingBottom">@dimen/call_detail_action_item_padding_vertical</item>
+    </style>
+
     <style name="DialtactsActionBarStyle"
            parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
         <!-- Styles that require AppCompat compatibility, remember to update both sets -->
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index 12849f4..73622bf 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -28,6 +28,7 @@
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -39,6 +40,7 @@
 import android.widget.Toast;
 
 import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.ClipboardUtils;
 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.GeoUtil;
@@ -52,6 +54,10 @@
 import com.android.dialer.calllog.CallTypeHelper;
 import com.android.dialer.calllog.ContactInfoHelper;
 import com.android.dialer.calllog.PhoneAccountUtils;
+import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
+import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
+import com.android.dialer.filterednumber.FilterNumberDialogFragment;
+import com.android.dialer.util.DialerUtils;
 import com.android.dialer.util.IntentUtil.CallIntentBuilder;
 import com.android.dialer.util.PhoneNumberUtil;
 import com.android.dialer.util.TelecomUtil;
@@ -64,8 +70,10 @@
  * {@link #EXTRA_CALL_LOG_IDS} extra to specify a group of call log entries.
  */
 public class CallDetailActivity extends AppCompatActivity
-        implements MenuItem.OnMenuItemClickListener {
-    private static final String TAG = "CallDetail";
+        implements MenuItem.OnMenuItemClickListener, View.OnClickListener,
+                FilterNumberDialogFragment.OnBlockListener,
+                FilterNumberDialogFragment.OnUndoBlockListener {
+    private static final String TAG = CallDetailActivity.class.getSimpleName();
 
      /** A long array extra containing ids of call log entries to display. */
     public static final String EXTRA_CALL_LOG_IDS = "EXTRA_CALL_LOG_IDS";
@@ -97,31 +105,28 @@
                 return;
             }
 
-            // We know that all calls are from the same number and the same contact, so pick the
-            // first.
-            PhoneCallDetails firstDetails = details[0];
-            mNumber = TextUtils.isEmpty(firstDetails.number) ?
-                    null : firstDetails.number.toString();
-            final int numberPresentation = firstDetails.numberPresentation;
-            final Uri contactUri = firstDetails.contactUri;
-            final Uri photoUri = firstDetails.photoUri;
-            final PhoneAccountHandle accountHandle = firstDetails.accountHandle;
+            // All calls are from the same number and same contact, so pick the first detail.
+            mDetails = details[0];
+            mNumber = TextUtils.isEmpty(mDetails.number) ?
+                    null : mDetails.number.toString();
+            mDisplayNumber = mDetails.displayNumber;
+            final int numberPresentation = mDetails.numberPresentation;
+            final Uri contactUri = mDetails.contactUri;
+            final Uri photoUri = mDetails.photoUri;
+            final PhoneAccountHandle accountHandle = mDetails.accountHandle;
 
             // Cache the details about the phone number.
-            final boolean canPlaceCallsTo =
-                    PhoneNumberUtil.canPlaceCallsTo(mNumber, numberPresentation);
             mIsVoicemailNumber =
                     PhoneNumberUtil.isVoicemailNumber(mContext, accountHandle, mNumber);
-            final boolean isSipNumber = PhoneNumberUtil.isSipNumber(mNumber);
 
-            final CharSequence callLocationOrType = getNumberTypeOrLocation(firstDetails);
+            final CharSequence callLocationOrType = getNumberTypeOrLocation(mDetails);
 
-            final CharSequence displayNumber = firstDetails.displayNumber;
+            final CharSequence displayNumber = mDetails.displayNumber;
             final String displayNumberStr = mBidiFormatter.unicodeWrap(
                     displayNumber.toString(), TextDirectionHeuristics.LTR);
 
-            if (!TextUtils.isEmpty(firstDetails.name)) {
-                mCallerName.setText(firstDetails.name);
+            if (!TextUtils.isEmpty(mDetails.name)) {
+                mCallerName.setText(mDetails.name);
                 mCallerNumber.setText(callLocationOrType + " " + displayNumberStr);
             } else {
                 mCallerName.setText(displayNumberStr);
@@ -133,8 +138,6 @@
                 }
             }
 
-            mCallButton.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
-
             String accountLabel = PhoneAccountUtils.getAccountLabel(mContext, accountHandle);
             if (!TextUtils.isEmpty(accountLabel)) {
                 mAccountLabel.setText(accountLabel);
@@ -143,20 +146,31 @@
                 mAccountLabel.setVisibility(View.GONE);
             }
 
-            mHasEditNumberBeforeCallOption =
+            final boolean canPlaceCallsTo =
+                    PhoneNumberUtil.canPlaceCallsTo(mNumber, mDetails.numberPresentation);
+            mCallButton.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
+
+            final boolean isSipNumber = PhoneNumberUtil.isSipNumber(mNumber);
+            final boolean showEditNumberBeforeCallAction =
                     canPlaceCallsTo && !isSipNumber && !mIsVoicemailNumber;
-            mHasReportMenuOption = mContactInfoHelper.canReportAsInvalid(
-                    firstDetails.sourceType, firstDetails.objectId);
+            mEditBeforeCallActionItem.setVisibility(
+                    showEditNumberBeforeCallAction ? View.VISIBLE : View.GONE);
+
+            final boolean showReportAction = mContactInfoHelper.canReportAsInvalid(
+                    mDetails.sourceType, mDetails.objectId);
+            mReportActionItem.setVisibility(
+                    showReportAction ? View.VISIBLE : View.GONE);
+
+            updateBlockActionItem();
             invalidateOptionsMenu();
 
-            ListView historyList = (ListView) findViewById(R.id.history);
-            historyList.setAdapter(
+            mHistoryList.setAdapter(
                     new CallDetailHistoryAdapter(mContext, mInflater, mCallTypeHelper, details));
 
             String lookupKey = contactUri == null ? null
                     : UriUtils.getLookupKeyFromUri(contactUri);
 
-            final boolean isBusiness = mContactInfoHelper.isBusiness(firstDetails.sourceType);
+            final boolean isBusiness = mContactInfoHelper.isBusiness(mDetails.sourceType);
 
             final int contactType =
                     mIsVoicemailNumber ? ContactPhotoManager.TYPE_VOICEMAIL :
@@ -164,10 +178,10 @@
                     ContactPhotoManager.TYPE_DEFAULT;
 
             String nameForDefaultImage;
-            if (TextUtils.isEmpty(firstDetails.name)) {
-                nameForDefaultImage = firstDetails.displayNumber;
+            if (TextUtils.isEmpty(mDetails.name)) {
+                nameForDefaultImage = mDetails.displayNumber;
             } else {
-                nameForDefaultImage = firstDetails.name.toString();
+                nameForDefaultImage = mDetails.name.toString();
             }
 
             loadContactPhotos(
@@ -193,29 +207,34 @@
     };
 
     private Context mContext;
+    private ContactInfoHelper mContactInfoHelper;
     private CallTypeHelper mCallTypeHelper;
+    private ContactPhotoManager mContactPhotoManager;
+    private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
+    private BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
+    private LayoutInflater mInflater;
+    private Resources mResources;
+
+    private PhoneCallDetails mDetails;
+    protected String mNumber;
+    private Uri mVoicemailUri;
+    private boolean mIsVoicemailNumber;
+    private String mDefaultCountryIso;
+    private String mDisplayNumber;
+
+    private ListView mHistoryList;
     private QuickContactBadge mQuickContactBadge;
     private TextView mCallerName;
     private TextView mCallerNumber;
     private TextView mAccountLabel;
     private View mCallButton;
-    private ContactInfoHelper mContactInfoHelper;
 
-    protected String mNumber;
-    private boolean mIsVoicemailNumber;
-    private String mDefaultCountryIso;
+    private View mBlockNumberActionItem;
+    private TextView mBlockNumberActionItemText;
+    private View mEditBeforeCallActionItem;
+    private View mReportActionItem;
 
-    /* package */ LayoutInflater mInflater;
-    /* package */ Resources mResources;
-    /** Helper to load contact photos. */
-    private ContactPhotoManager mContactPhotoManager;
-
-    private Uri mVoicemailUri;
-    private BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
-
-    /** Whether we should show "edit number before call" in the options menu. */
-    private boolean mHasEditNumberBeforeCallOption;
-    private boolean mHasReportMenuOption;
+    private Integer mBlockedNumberId;
 
     @Override
     protected void onCreate(Bundle icicle) {
@@ -227,18 +246,23 @@
         }
 
         mContext = this;
-
-        setContentView(R.layout.call_detail);
-
-        mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
         mResources = getResources();
-
+        mContactInfoHelper = new ContactInfoHelper(this, GeoUtil.getCurrentCountryIso(this));
         mCallTypeHelper = new CallTypeHelper(getResources());
+        mFilteredNumberAsyncQueryHandler =
+                new FilteredNumberAsyncQueryHandler(getContentResolver());
 
         mVoicemailUri = getIntent().getParcelableExtra(EXTRA_VOICEMAIL_URI);
 
-        ListView historyList = (ListView) findViewById(R.id.history);
-        historyList.addHeaderView(mInflater.inflate(R.layout.call_detail_header, null));
+        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+        setContentView(R.layout.call_detail);
+        mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+
+        mHistoryList = (ListView) findViewById(R.id.history);
+        mHistoryList.addHeaderView(mInflater.inflate(R.layout.call_detail_header, null));
+        mHistoryList.addFooterView(
+                mInflater.inflate(R.layout.call_detail_footer, null), null, false);
 
         mQuickContactBadge = (QuickContactBadge) findViewById(R.id.quick_contact_photo);
         mQuickContactBadge.setOverlay(null);
@@ -260,8 +284,16 @@
             }
         });
 
-        mContactInfoHelper = new ContactInfoHelper(this, GeoUtil.getCurrentCountryIso(this));
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        mBlockNumberActionItem = findViewById(R.id.call_detail_action_block);
+        mBlockNumberActionItem.setOnClickListener(this);
+        mBlockNumberActionItemText = (TextView) findViewById(R.id.call_detail_action_block_text);
+        mEditBeforeCallActionItem = findViewById(R.id.call_detail_action_edit_before_call);
+        mEditBeforeCallActionItem.setOnClickListener(this);
+        mReportActionItem = findViewById(R.id.call_detail_action_report);
+        mReportActionItem.setOnClickListener(this);
+
+        View copyActionItem = findViewById(R.id.call_detail_action_copy);
+        copyActionItem.setOnClickListener(this);
 
         if (getIntent().getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) {
             closeSystemDialogs();
@@ -275,6 +307,16 @@
     }
 
     @Override
+    public void onBlockComplete(Uri uri) {
+        updateBlockActionItem();
+    }
+
+    @Override
+    public void onUndoBlockComplete() {
+        updateBlockActionItem();
+    }
+
+    @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());
@@ -286,11 +328,6 @@
         CallLogAsyncTaskUtil.getCallDetails(this, getCallLogEntryUris(), mCallLogAsyncTaskListener);
     }
 
-    @NeededForTesting
-    public boolean hasVoicemail() {
-        return mVoicemailUri != null;
-    }
-
     /**
      * Returns the list of URIs to show.
      * <p>
@@ -341,22 +378,10 @@
         deleteMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         deleteMenuItem.setOnMenuItemClickListener(this);
 
-        getMenuInflater().inflate(R.menu.call_details_options, menu);
         return super.onCreateOptionsMenu(menu);
     }
 
     @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        menu.findItem(R.id.menu_edit_number_before_call)
-                .setVisible(mHasEditNumberBeforeCallOption)
-                .setOnMenuItemClickListener(this);
-        menu.findItem(R.id.menu_report)
-                .setVisible(mHasReportMenuOption)
-                .setOnMenuItemClickListener(this);
-        return super.onPrepareOptionsMenu(menu);
-    }
-
-    @Override
     public boolean onMenuItemClick(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.call_detail_delete_menu_item:
@@ -375,14 +400,65 @@
                             this, callIds.toString(), mCallLogAsyncTaskListener);
                 }
                 break;
-            case R.id.menu_edit_number_before_call:
-                startActivity(new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(mNumber)));
-                break;
         }
         return true;
     }
 
+    @Override
+    public void onClick(View view) {
+        switch(view.getId()) {
+            case R.id.call_detail_action_block:
+                // TODO: Use helper, this code is repeated in several places.
+                FilterNumberDialogFragment newFragment =
+                        FilterNumberDialogFragment.newInstance(
+                                mBlockedNumberId, null, mNumber, null, mDisplayNumber);
+                // TODO: Cleanup this listener pattern. This only works correctly for undoing
+                // blocking, not undoing unblocking.
+                newFragment.setOnBlockListener(this);
+                newFragment.setOnUndoBlockListener(this);
+                newFragment.setParentView(findViewById(R.id.call_detail));
+                newFragment.show(
+                        getFragmentManager(), FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
+                break;
+            case R.id.call_detail_action_copy:
+                ClipboardUtils.copyText(mContext, null, mNumber, true);
+                break;
+            case R.id.call_detail_action_edit_before_call:
+                Intent dialIntent = new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(mNumber));
+                DialerUtils.startActivityWithErrorToast(mContext, dialIntent);
+                break;
+            default:
+                Log.wtf(TAG, "Unexpected onClick event from " + view);
+                break;
+        }
+    }
+
+    private void updateBlockActionItem() {
+        if (mDetails == null) {
+            return;
+        }
+
+        mFilteredNumberAsyncQueryHandler.startBlockedQuery(new OnCheckBlockedListener() {
+            @Override
+            public void onCheckComplete(Integer id) {
+                mBlockedNumberId = id;
+                if (mBlockedNumberId == null) {
+                    mBlockNumberActionItemText.setText(R.string.action_block_number);
+                } else {
+                    mBlockNumberActionItemText.setText(R.string.action_unblock_number);
+                }
+
+                mBlockNumberActionItem.setVisibility(View.VISIBLE);
+            }
+        }, null, mNumber, mDetails.countryIso);
+    }
+
     private void closeSystemDialogs() {
         sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
     }
+
+    @NeededForTesting
+    public boolean hasVoicemail() {
+        return mVoicemailUri != null;
+    }
 }
diff --git a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
index d22947b..0e234e3 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
@@ -268,7 +268,7 @@
         }
 
         menu.add(ContextMenu.NONE, R.id.context_menu_copy_to_clipboard, ContextMenu.NONE,
-                R.string.copy_number_text)
+                R.string.action_copy_number_text)
                 .setOnMenuItemClickListener(this);
 
         // The edit number before call does not show up if any of the conditions apply:
@@ -280,7 +280,7 @@
                 && !mTelecomCallLogCache.isVoicemailNumber(accountHandle, number)
                 && !PhoneNumberUtil.isSipNumber(number)) {
             menu.add(ContextMenu.NONE, R.id.context_menu_edit_before_call, ContextMenu.NONE,
-                    R.string.call_log_edit_number_before_call)
+                    R.string.action_edit_number_before_call)
                     .setOnMenuItemClickListener(this);
         }
 
@@ -296,8 +296,8 @@
                     @Override
                     public void onCheckComplete(Integer id) {
                         blockId = id;
-                        int blockTitleId = blockId == null ? R.string.call_log_block_number
-                                : R.string.call_log_unblock_number;
+                        int blockTitleId = blockId == null ? R.string.action_block_number
+                                : R.string.action_unblock_number;
                         final MenuItem blockItem = menu.add(
                                 ContextMenu.NONE,
                                 R.id.context_menu_block_number,
diff --git a/tests/src/com/android/dialer/CallDetailActivityTest.java b/tests/src/com/android/dialer/CallDetailActivityTest.java
index eda7474..c310c88 100644
--- a/tests/src/com/android/dialer/CallDetailActivityTest.java
+++ b/tests/src/com/android/dialer/CallDetailActivityTest.java
@@ -16,7 +16,7 @@
 
 package com.android.dialer;
 
-import static com.android.dialer.calllog.CallLogAsyncTaskUtil.Tasks.GET_CALL_DETAILS;
+import static com.android.dialer.calllog.CallLogAsyncTaskUtil.Tasks;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
@@ -89,14 +89,20 @@
     public void testVoicemailDeleteButton() throws Throwable {
         setActivityIntentForTestVoicemailEntry();
         startActivityUnderTest();
-        mFakeAsyncTaskExecutor.runTask(GET_CALL_DETAILS);
+        mFakeAsyncTaskExecutor.runTask(Tasks.GET_CALL_DETAILS);
 
         Menu optionsMenu = (new PopupMenu(mActivityUnderTest, null)).getMenu();
         mActivityUnderTest.onCreateOptionsMenu(optionsMenu);
         mActivityUnderTest.onPrepareOptionsMenu(optionsMenu);
 
-        assertTrue(optionsMenu.findItem(R.id.call_detail_delete_menu_item).isVisible());
         assertTrue(mActivityUnderTest.hasVoicemail());
+        mActivityUnderTest.runOnUiThread(new Runnable() {
+            public void run() {
+                mActivityUnderTest.findViewById(R.id.call_detail_delete_menu_item).performClick();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        mFakeAsyncTaskExecutor.runTask(Tasks.DELETE_VOICEMAIL);
     }
 
     /**
@@ -105,14 +111,20 @@
     public void testRegularCallDoesHaveRemoveFromCallLog() throws Throwable {
         setActivityIntentForTestCallEntry();
         startActivityUnderTest();
-        mFakeAsyncTaskExecutor.runTask(GET_CALL_DETAILS);
+        mFakeAsyncTaskExecutor.runTask(Tasks.GET_CALL_DETAILS);
 
         Menu optionsMenu = (new PopupMenu(mActivityUnderTest, null)).getMenu();
         mActivityUnderTest.onCreateOptionsMenu(optionsMenu);
         mActivityUnderTest.onPrepareOptionsMenu(optionsMenu);
 
-        assertTrue(optionsMenu.findItem(R.id.call_detail_delete_menu_item).isVisible());
         assertFalse(mActivityUnderTest.hasVoicemail());
+        mActivityUnderTest.runOnUiThread(new Runnable() {
+            public void run() {
+                mActivityUnderTest.findViewById(R.id.call_detail_delete_menu_item).performClick();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        mFakeAsyncTaskExecutor.runTask(Tasks.DELETE_CALL);
     }
 
     private void setActivityIntentForTestCallEntry() {