conversation: copy peers number to clipboard

This patch introduces the ability to copy a peer's number in a conver-
sation context.
It can be trigger by longpressing a conversation in the Smartlist or
by selecting the entry in the options of the opened conversation it-
self.
The layout basically the same as the dropdown menu used to select the
peer number in the conversation activity.

Change-Id: Ia1927e9de6317c5b22409ef5a5fdefe67f991ea4
Tuleap: #639
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java
index 0404dc7..adc447e 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java
@@ -41,6 +41,7 @@
 import java.util.concurrent.ExecutorService;
 
 import cx.ring.R;
+import cx.ring.model.CallContact;
 import cx.ring.model.Conversation;
 import cx.ring.model.TextMessage;
 import cx.ring.views.ConversationViewHolder;
@@ -208,7 +209,7 @@
 
         int pictureResID;
         String histTxt;
-        String callNumber = convElement.call.getShortenedNumber();
+        String callNumber = CallContact.Phone.getShortenedNumber(convElement.call.number);
         convViewHolder.mPhoto.setScaleY(1);
         if (convElement.call.isMissed()) {
             if (convElement.call.isIncoming()) {
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/NumberAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/NumberAdapter.java
new file mode 100644
index 0000000..3984d63
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/adapters/NumberAdapter.java
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (C) 2015-2016 Savoir-faire Linux Inc.
+ *
+ *  Authors:    Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *              Romain Bertozzi <romain.bertozzi@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.adapters;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+import cx.ring.R;
+import cx.ring.model.CallContact;
+
+public class NumberAdapter extends BaseAdapter {
+    final private Context mContext;
+    final private ArrayList<CallContact.Phone> mNumbers;
+    private boolean mUseFullCellForGetView = false;
+
+    public NumberAdapter(Context context, CallContact c, boolean useFullCellForGetView) {
+        mContext = context;
+        mNumbers = (c != null && c.getPhones() != null) ?
+                c.getPhones() : new ArrayList<CallContact.Phone>();
+        mUseFullCellForGetView = useFullCellForGetView;
+    }
+
+    @Override
+    public int getCount() {
+        return mNumbers.size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mNumbers.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return 0;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        return this.getViewWithLongNumber(this.mUseFullCellForGetView, position, convertView, parent);
+    }
+
+    @Override
+    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+        return this.getViewWithLongNumber(true, position, convertView, parent);
+    }
+
+    private View getViewWithLongNumber(boolean longView, int position, View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            if (longView) {
+                convertView = LayoutInflater.from(mContext).inflate(R.layout.item_number, parent,
+                        false);
+            } else {
+                convertView = LayoutInflater.from(mContext).inflate(R.layout.item_number_selected,
+                        parent, false);
+            }
+        }
+
+        CallContact.Phone number = mNumbers.get(position);
+        ImageView numberIcon = (ImageView) convertView.findViewById(R.id.number_icon);
+        numberIcon.setImageResource(number.getNumber().isRingId() ?
+                R.drawable.ring_logo_24dp : R.drawable.ic_dialer_sip_black_24dp);
+
+        if (longView) {
+            TextView numberTxt = (TextView) convertView.findViewById(R.id.number_txt);
+            TextView numberLabelTxt = (TextView) convertView.findViewById(R.id.number_label_txt);
+
+            numberTxt.setText(number.getNumber().getRawUriString());
+            numberLabelTxt.setText(number.getTypeString(mContext.getResources()));
+        }
+
+        return convertView;
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java b/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
index c7800b0..2f17f6e 100644
--- a/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
@@ -24,7 +24,6 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
@@ -33,8 +32,8 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.SystemClock;
+import android.support.design.widget.Snackbar;
 import android.support.v7.app.ActionBar;
-import android.support.v7.app.AlertDialog;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.LinearLayoutManager;
@@ -42,33 +41,32 @@
 import android.util.Log;
 import android.util.Pair;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
-import android.widget.BaseAdapter;
 import android.widget.EditText;
-import android.widget.ImageView;
 import android.widget.Spinner;
 import android.widget.TextView;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import cx.ring.R;
 import cx.ring.adapters.ConversationAdapter;
+import cx.ring.adapters.NumberAdapter;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.Conversation;
 import cx.ring.model.SipUri;
 import cx.ring.model.account.Account;
 import cx.ring.service.LocalService;
+import cx.ring.utils.ClipboardHelper;
 
 public class ConversationActivity extends AppCompatActivity implements
-        Conversation.ConversationActionCallback {
+        Conversation.ConversationActionCallback,
+        ClipboardHelper.ClipboardHelperCallback {
     private static final String TAG = ConversationActivity.class.getSimpleName();
 
     public static final Uri CONTENT_URI = Uri.withAppendedPath(LocalService.AUTHORITY_URI,
@@ -172,7 +170,9 @@
 
         if (mConversation.getContact().getPhones().size() > 1) {
             mNumberSpinner.setVisibility(View.VISIBLE);
-            mNumberAdapter = new NumberAdapter(ConversationActivity.this, mConversation.getContact());
+            mNumberAdapter = new NumberAdapter(ConversationActivity.this,
+                    mConversation.getContact(),
+                    false);
             mNumberSpinner.setAdapter(mNumberAdapter);
             if (mPreferredNumber == null || mPreferredNumber.isEmpty()) {
                 mPreferredNumber = new SipUri(
@@ -344,67 +344,6 @@
         }
     }
 
-    private class NumberAdapter extends BaseAdapter {
-        final private Context context;
-        private ArrayList<CallContact.Phone> numbers;
-
-        NumberAdapter(Context context, CallContact c) {
-            this.context = context;
-            numbers = c.getPhones();
-        }
-
-        @Override
-        public int getCount() {
-            return numbers.size();
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return numbers.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return 0;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null)
-                convertView = LayoutInflater.from(context).inflate(R.layout.item_number_selected,
-                        parent, false);
-
-            CallContact.Phone number = numbers.get(position);
-
-            ImageView numberIcon = (ImageView) convertView.findViewById(R.id.number_icon);
-            numberIcon.setImageResource(number.getNumber().isRingId() ?
-                    R.drawable.ring_logo_24dp : R.drawable.ic_dialer_sip_black_24dp);
-
-            return convertView;
-        }
-
-        @Override
-        public View getDropDownView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null)
-                convertView = LayoutInflater.from(context).inflate(R.layout.item_number, parent, false);
-
-            CallContact.Phone number = numbers.get(position);
-
-            TextView numberTxt = (TextView) convertView.findViewById(R.id.number_txt);
-            TextView numberLabelTxt = (TextView) convertView.findViewById(R.id.number_label_txt);
-            ImageView numberIcon = (ImageView) convertView.findViewById(R.id.number_icon);
-
-            numberTxt.setText(number.getNumber().getRawUriString());
-            numberLabelTxt.setText(number.getTypeString(context.getResources()));
-            numberIcon.setImageResource(
-                    number.getNumber().isRingId() ?
-                            R.drawable.ring_logo_24dp : R.drawable.ic_dialer_sip_black_24dp
-            );
-
-            return convertView;
-        }
-    }
-
     @Override
     protected void onDestroy() {
         if (mBound) {
@@ -445,6 +384,10 @@
             case R.id.menuitem_delete:
                 Conversation.launchDeleteAction(this, this.mConversation, this);
                 return true;
+            case R.id.menuitem_copy_content:
+                Conversation.launchCopyNumberToClipboardFromContact(this,
+                        this.mConversation.getContact(), this);
+                return true;
             default:
                 return super.onOptionsItemSelected(item);
         }
@@ -527,4 +470,19 @@
         }
         finish();
     }
+
+    @Override
+    public void copyContactNumberToClipboard(String contactNumber) {
+        ClipboardHelper.copyNumberToClipboard(this, contactNumber, this);
+    }
+
+    @Override
+    public void clipBoardDidCopyNumber(String copiedNumber) {
+        View view = this.findViewById(android.R.id.content);
+        if (view != null) {
+            String snackbarText = getString(R.string.conversation_action_copied_peer_number_clipboard,
+                    CallContact.Phone.getShortenedNumber(copiedNumber));
+            Snackbar.make(view, snackbarText, Snackbar.LENGTH_LONG).show();
+        }
+    }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
index 8c645fc..e40ba70 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
@@ -32,6 +32,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.support.design.widget.FloatingActionButton;
+import android.support.design.widget.Snackbar;
 import android.support.v4.view.MenuItemCompat;
 import android.support.v7.widget.SearchView;
 import android.support.v7.widget.Toolbar;
@@ -63,10 +64,13 @@
 import cx.ring.model.Conference;
 import cx.ring.model.Conversation;
 import cx.ring.service.LocalService;
+import cx.ring.utils.ClipboardHelper;
 
 public class SmartListFragment extends Fragment implements SearchView.OnQueryTextListener,
         HomeActivity.Refreshable,
-        SmartListAdapter.SmartListAdapterCallback {
+        SmartListAdapter.SmartListAdapterCallback,
+        Conversation.ConversationActionCallback,
+        ClipboardHelper.ClipboardHelperCallback {
     private static final String TAG = SmartListFragment.class.getSimpleName();
 
     private static final int USER_INPUT_DELAY = 300;
@@ -288,6 +292,7 @@
 
         mList = (ListView) inflatedView.findViewById(cx.ring.R.id.confs_list);
         mList.setOnItemClickListener(conversationClickListener);
+        mList.setOnItemLongClickListener(conversationLongClickListener);
 
         this.mEmptyTextView = (TextView) inflatedView.findViewById(R.id.emptyTextView);
         this.mLoader = inflatedView.findViewById(android.R.id.empty);
@@ -354,6 +359,17 @@
         }
     };
 
+    private final AdapterView.OnItemLongClickListener conversationLongClickListener =
+            new AdapterView.OnItemLongClickListener() {
+                @Override
+                public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
+                    Conversation.presentActions(getActivity(),
+                            ((SmartListAdapter.ViewHolder) v.getTag()).conv,
+                            SmartListFragment.this);
+                    return true;
+                }
+            };
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
@@ -529,4 +545,26 @@
     }
 
     //endregion
+
+
+    @Override
+    public void deleteConversation(Conversation conversation) {
+        if (mCallbacks.getService() != null) {
+            mCallbacks.getService().deleteConversation(conversation);
+        }
+    }
+
+    @Override
+    public void copyContactNumberToClipboard(String contactNumber) {
+        ClipboardHelper.copyNumberToClipboard(getActivity(), contactNumber, this);
+    }
+
+    @Override
+    public void clipBoardDidCopyNumber(String copiedNumber) {
+        if (getView() != null) {
+            String snackbarText = getString(R.string.conversation_action_copied_peer_number_clipboard,
+                    CallContact.Phone.getShortenedNumber(copiedNumber));
+            Snackbar.make(getView(), snackbarText, Snackbar.LENGTH_LONG).show();
+        }
+    }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java b/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java
index 4027524..f5f88f1 100644
--- a/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java
+++ b/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java
@@ -149,13 +149,6 @@
         return number;
     }
 
-    public String getShortenedNumber() {
-        if (number.length() > 18) {
-            return number.substring(0, 18).concat("…");
-        }
-        return number;
-    }
-
     @Override
     public int describeContents() {
         return 0;
diff --git a/ring-android/app/src/main/java/cx/ring/model/CallContact.java b/ring-android/app/src/main/java/cx/ring/model/CallContact.java
index eea5a53..004bc09 100644
--- a/ring-android/app/src/main/java/cx/ring/model/CallContact.java
+++ b/ring-android/app/src/main/java/cx/ring/model/CallContact.java
@@ -37,6 +37,7 @@
 import android.provider.ContactsContract.Profile;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
@@ -396,6 +397,13 @@
         public CharSequence getTypeString(Resources r) {
             return ContactsContract.CommonDataKinds.Phone.getTypeLabel(r, category, label);
         }
+
+        public static String getShortenedNumber(String number) {
+            if (!TextUtils.isEmpty(number) && number.length() > 18) {
+                return number.substring(0, 18).concat("…");
+            }
+            return number;
+        }
     }
 
     public void addPhoneNumber(String tel) {
diff --git a/ring-android/app/src/main/java/cx/ring/model/Conversation.java b/ring-android/app/src/main/java/cx/ring/model/Conversation.java
index c2b72c3..3f28b1f 100644
--- a/ring-android/app/src/main/java/cx/ring/model/Conversation.java
+++ b/ring-android/app/src/main/java/cx/ring/model/Conversation.java
@@ -41,6 +41,7 @@
 import java.util.TreeMap;
 
 import cx.ring.R;
+import cx.ring.adapters.NumberAdapter;
 import cx.ring.history.HistoryCall;
 import cx.ring.history.HistoryEntry;
 
@@ -262,6 +263,8 @@
 
     public interface ConversationActionCallback {
         void deleteConversation(Conversation conversation);
+
+        void copyContactNumberToClipboard(String contactNumber);
     }
 
     public static void launchDeleteAction(final Activity activity,
@@ -283,9 +286,9 @@
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int whichButton) {
-                            if (callback != null) {
-                                callback.deleteConversation(conversation);
-                            }
+                        if (callback != null) {
+                            callback.deleteConversation(conversation);
+                        }
                     }
                 })
                 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -298,4 +301,79 @@
         AlertDialog alertDialog = builder.create();
         alertDialog.show();
     }
+
+    public static void presentActions(final Activity activity,
+                                      final Conversation conversation,
+                                      final ConversationActionCallback callback) {
+        if (activity == null) {
+            Log.d(TAG, "presentActions: activity is null");
+            return;
+        }
+
+        if (conversation == null) {
+            Log.d(TAG, "presentActions: conversation is null");
+            return;
+        }
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setItems(R.array.conversation_actions, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                switch (which) {
+                    case 0:
+                        launchCopyNumberToClipboardFromContact(activity,
+                                conversation.contact,
+                                callback);
+                        break;
+                    case 1:
+                        launchDeleteAction(activity, conversation, callback);
+                        break;
+                }
+            }
+        });
+        AlertDialog dialog = builder.create();
+        dialog.show();
+    }
+
+    public static void launchCopyNumberToClipboardFromContact(final Activity activity,
+                                                              final CallContact callContact,
+                                                              final ConversationActionCallback callback) {
+        if (callContact == null) {
+            Log.d(TAG, "launchCopyNumberToClipboardFromContact: callContact is null");
+            return;
+        }
+
+        if (activity == null) {
+            Log.d(TAG, "launchCopyNumberToClipboardFromContact: activity is null");
+            return;
+        }
+
+        if (callContact.getPhones().isEmpty()) {
+            Log.d(TAG, "launchCopyNumberToClipboardFromContact: no number to copy");
+            return;
+        } else if (callContact.getPhones().size() == 1 && callback != null) {
+            String number = callContact.getPhones().get(0).getNumber().toString();
+            callback.copyContactNumberToClipboard(number);
+            return;
+        }
+
+        final NumberAdapter adapter = new NumberAdapter(activity, callContact, true);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setTitle(R.string.conversation_action_select_peer_number);
+        builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (callback != null) {
+                    CallContact.Phone selectedPhone = (CallContact.Phone) adapter.getItem(which);
+                    callback.copyContactNumberToClipboard(selectedPhone.getNumber().toString());
+                }
+            }
+        });
+        AlertDialog dialog = builder.create();
+        final int listViewSidePadding = (int) activity
+                .getResources()
+                .getDimension(R.dimen.alert_dialog_side_padding_list_view);
+        dialog.getListView().setPadding(listViewSidePadding, 0, listViewSidePadding, 0);
+        dialog.show();
+    }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/utils/ClipboardHelper.java b/ring-android/app/src/main/java/cx/ring/utils/ClipboardHelper.java
new file mode 100644
index 0000000..c0fd294
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/ClipboardHelper.java
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (C) 2015-2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Romain Bertozzi <romain.bertozzi@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.utils;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import cx.ring.BuildConfig;
+
+public class ClipboardHelper {
+    public static final String TAG = ClipboardHelper.class.getSimpleName();
+    public static final String COPY_CALL_CONTACT_NUMBER_CLIP_LABEL =
+            BuildConfig.APPLICATION_ID + ".clipboard.contactNumber";
+
+    public interface ClipboardHelperCallback {
+        void clipBoardDidCopyNumber(String copiedNumber);
+    }
+
+    public static void copyNumberToClipboard(final Activity activity,
+                                             final String number,
+                                             final ClipboardHelperCallback callback) {
+        if (TextUtils.isEmpty(number)) {
+            Log.d(TAG, "copyNumberToClipboard: number is null");
+            return;
+        }
+
+        if (activity == null) {
+            Log.d(TAG, "copyNumberToClipboard: activity is null");
+            return;
+        }
+
+        ClipboardManager clipboard = (ClipboardManager) activity
+                .getSystemService(Context.CLIPBOARD_SERVICE);
+        ClipData clip = android.content.ClipData.newPlainText(COPY_CALL_CONTACT_NUMBER_CLIP_LABEL,
+                number);
+        clipboard.setPrimaryClip(clip);
+        if (callback != null) {
+            callback.clipBoardDidCopyNumber(number);
+        }
+    }
+}
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png
new file mode 100644
index 0000000..70eb073
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-hdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-hdpi/ic_send_black_24dp.png
deleted file mode 100644
index e65515d..0000000
--- a/ring-android/app/src/main/res/drawable-ldrtl-hdpi/ic_send_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-mdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-mdpi/ic_send_black_24dp.png
deleted file mode 100644
index d65d822..0000000
--- a/ring-android/app/src/main/res/drawable-ldrtl-mdpi/ic_send_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-xhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-xhdpi/ic_send_black_24dp.png
deleted file mode 100644
index 3a25fbb..0000000
--- a/ring-android/app/src/main/res/drawable-ldrtl-xhdpi/ic_send_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-xxhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-xxhdpi/ic_send_black_24dp.png
deleted file mode 100644
index 89afc01..0000000
--- a/ring-android/app/src/main/res/drawable-ldrtl-xxhdpi/ic_send_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-xxxhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-xxxhdpi/ic_send_black_24dp.png
deleted file mode 100644
index def070f..0000000
--- a/ring-android/app/src/main/res/drawable-ldrtl-xxxhdpi/ic_send_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png
new file mode 100644
index 0000000..80c0695
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png
new file mode 100644
index 0000000..537fd4e
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png
new file mode 100644
index 0000000..9dff893
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png
new file mode 100644
index 0000000..4ddee9e
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/layout/item_number.xml b/ring-android/app/src/main/res/layout/item_number.xml
index 17bc481..782b590 100644
--- a/ring-android/app/src/main/res/layout/item_number.xml
+++ b/ring-android/app/src/main/res/layout/item_number.xml
@@ -40,7 +40,7 @@
 
     <TextView
         android:id="@+id/number_txt"
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         android:layout_marginTop="2dp"
@@ -51,17 +51,19 @@
         android:singleLine="true"
         android:text="+15142792035"
         android:textColor="@color/text_color_primary"
-        android:textSize="16sp" />
+        android:textSize="16sp"
+        android:layout_marginRight="8dp" />
 
     <TextView
         android:id="@+id/number_label_txt"
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@+id/number_txt"
         android:layout_toEndOf="@+id/number_icon"
         android:layout_toRightOf="@+id/number_icon"
         android:text="Inde"
         android:textColor="@color/text_color_secondary"
-        android:textSize="12sp" />
+        android:textSize="12sp"
+        android:layout_marginRight="8dp" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/menu/conversation_actions.xml b/ring-android/app/src/main/res/menu/conversation_actions.xml
index 239b7f0..0558543 100644
--- a/ring-android/app/src/main/res/menu/conversation_actions.xml
+++ b/ring-android/app/src/main/res/menu/conversation_actions.xml
@@ -21,6 +21,12 @@
         app:showAsAction="always" />
 
     <item
+        android:id="@+id/menuitem_copy_content"
+        android:icon="@drawable/ic_content_copy_white_24dp"
+        android:title="@string/conversation_action_copy_peer_number"
+        app:showAsAction="ifRoom" />
+
+    <item
         android:id="@+id/menuitem_delete"
         android:icon="@drawable/ic_delete_white_24dp"
         android:title="@string/conversation_action_delete_this"
diff --git a/ring-android/app/src/main/res/values/arrays.xml b/ring-android/app/src/main/res/values/arrays.xml
index 7082798..dbc2806 100644
--- a/ring-android/app/src/main/res/values/arrays.xml
+++ b/ring-android/app/src/main/res/values/arrays.xml
@@ -50,4 +50,9 @@
         <item>SIP</item>
     </string-array>
 
+    <string-array name="conversation_actions">
+        <item>@string/conversation_action_copy_peer_number</item>
+        <item>@string/conversation_action_delete_this</item>
+    </string-array>
+
 </resources>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values/dimens.xml b/ring-android/app/src/main/res/values/dimens.xml
index d3ad642..fc5c17a 100644
--- a/ring-android/app/src/main/res/values/dimens.xml
+++ b/ring-android/app/src/main/res/values/dimens.xml
@@ -1,22 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2004-2016 Savoir-faire Linux Inc.
-                                                                    
+
 Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
-                                                                    
+
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or   
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
-                                                                    
-This program is distributed in the hope that it will be useful,     
-but WITHOUT ANY WARRANTY; without even the implied warranty of      
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       
-GNU General Public License for more details.                        
-                                                                    
-You should have received a copy of the GNU General Public License   
-along with this program; if not, write to the Free Software         
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 -->
 <resources>
 
@@ -32,13 +32,12 @@
 
     <dimen name="activity_horizontal_margin">16dp</dimen>
     <dimen name="activity_vertical_margin">16dp</dimen>
-    
+
     <dimen name="contact_drawer_handle_height">36dp</dimen>
     <dimen name="contact_drawer_handle_height_with_shadow">40dp</dimen>
 
     <dimen name="contact_vertical_spacing">16dp</dimen>
-    
-    
+
     <dimen name="header_history_detail">200dp</dimen>
 
     <dimen name="action_button_lpadding">0dp</dimen>
@@ -47,4 +46,6 @@
 
     <dimen name="action_bar_title_margin_bottom">16dp</dimen>
 
+    <dimen name="alert_dialog_side_padding_list_view">16dp</dimen>
+
 </resources>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index 6276643..1c57aca 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -157,6 +157,9 @@
     <string name="conversation_action_delete_this">Delete this conversation</string>
     <string name="conversation_action_delete_this_title">Delete this conversation ?</string>
     <string name="conversation_action_delete_this_message">This action can not be undone.</string>
+    <string name="conversation_action_copy_peer_number">Copy number</string>
+    <string name="conversation_action_copied_peer_number_clipboard">%1$s copied to clipboard</string>
+    <string name="conversation_action_select_peer_number">Select a number</string>
 
     <!-- Contacts -->
     <string name="add_call_contact_number_to_contacts">Add %1$s ?</string>