diff --git a/res/layout/verify_display_fragment.xml b/res/layout/verify_display_fragment.xml index 8a3067b487..67203b9843 100644 --- a/res/layout/verify_display_fragment.xml +++ b/res/layout/verify_display_fragment.xml @@ -48,11 +48,17 @@ - + android:layout_marginTop="5dp" + android:clickable="true" + android:focusable="true"> + + - + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index f01fbfece9..46c95598ec 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -569,6 +569,7 @@ Share safety numbers via... Our Signal safety numbers: It looks like you don\'t have any apps to share to. + No safety numbers to compare were found in the clipboard Initiate despite existing request? @@ -1210,6 +1211,10 @@ Invite friends Help + + Copy to clipboard + Compare with clipboard + Your version of Signal is outdated @@ -1268,7 +1273,6 @@ Transport icon - diff --git a/res/values/styles.xml b/res/values/styles.xml index 3b466a9c72..b29d1d6923 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -231,6 +231,8 @@ monospace monospace 17sp + false + false diff --git a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java index 22284bc805..a3d5548f50 100644 --- a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java @@ -34,8 +34,11 @@ import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.text.Html; +import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -46,6 +49,7 @@ import android.view.animation.Animation; import android.view.animation.AnticipateInterpolator; import android.view.animation.OvershootInterpolator; import android.view.animation.ScaleAnimation; +import android.widget.AdapterView; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; @@ -226,6 +230,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity private Fingerprint fingerprint; private View container; + private View numbersContainer; private ImageView qrCode; private ImageView qrVerified; private TextView description; @@ -237,24 +242,26 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity @Override public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) { - this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_display_fragment); - this.qrCode = ViewUtil.findById(container, R.id.qr_code); - this.qrVerified = ViewUtil.findById(container, R.id.qr_verified); - this.description = ViewUtil.findById(container, R.id.description); - this.codes[0] = ViewUtil.findById(container, R.id.code_first); - this.codes[1] = ViewUtil.findById(container, R.id.code_second); - this.codes[2] = ViewUtil.findById(container, R.id.code_third); - this.codes[3] = ViewUtil.findById(container, R.id.code_fourth); - this.codes[4] = ViewUtil.findById(container, R.id.code_fifth); - this.codes[5] = ViewUtil.findById(container, R.id.code_sixth); - this.codes[6] = ViewUtil.findById(container, R.id.code_seventh); - this.codes[7] = ViewUtil.findById(container, R.id.code_eighth); - this.codes[8] = ViewUtil.findById(container, R.id.code_ninth); - this.codes[9] = ViewUtil.findById(container, R.id.code_tenth); - this.codes[10] = ViewUtil.findById(container, R.id.code_eleventh); - this.codes[11] = ViewUtil.findById(container, R.id.code_twelth); + this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_display_fragment); + this.numbersContainer = ViewUtil.findById(container, R.id.number_table); + this.qrCode = ViewUtil.findById(container, R.id.qr_code); + this.qrVerified = ViewUtil.findById(container, R.id.qr_verified); + this.description = ViewUtil.findById(container, R.id.description); + this.codes[0] = ViewUtil.findById(container, R.id.code_first); + this.codes[1] = ViewUtil.findById(container, R.id.code_second); + this.codes[2] = ViewUtil.findById(container, R.id.code_third); + this.codes[3] = ViewUtil.findById(container, R.id.code_fourth); + this.codes[4] = ViewUtil.findById(container, R.id.code_fifth); + this.codes[5] = ViewUtil.findById(container, R.id.code_sixth); + this.codes[6] = ViewUtil.findById(container, R.id.code_seventh); + this.codes[7] = ViewUtil.findById(container, R.id.code_eighth); + this.codes[8] = ViewUtil.findById(container, R.id.code_ninth); + this.codes[9] = ViewUtil.findById(container, R.id.code_tenth); + this.codes[10] = ViewUtil.findById(container, R.id.code_eleventh); + this.codes[11] = ViewUtil.findById(container, R.id.code_twelth); this.qrCode.setOnClickListener(clickListener); + this.registerForContextMenu(numbersContainer); return container; } @@ -305,6 +312,26 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity recipient.removeListener(this); } + @Override + public void onCreateContextMenu(ContextMenu menu, View view, + ContextMenuInfo menuInfo) + { + super.onCreateContextMenu(menu, view, menuInfo); + + MenuInflater inflater = getActivity().getMenuInflater(); + inflater.inflate(R.menu.verify_display_fragment_context_menu, menu); + + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_copy: handleCopyToClipboard(); return true; + case R.id.menu_compare: handleCompareWithClipboard(); return true; + default: return super.onContextItemSelected(item); + } + } + public void setScannedFingerprint(String scanned) { try { if (fingerprint.getScannableFingerprint().compareTo(scanned.getBytes("ISO-8859-1"))) { @@ -346,6 +373,32 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity return result.toString(); } + private void handleCopyToClipboard() { + Util.writeTextToClipboard(getActivity(), getFormattedSafetyNumbers()); + } + + private void handleCompareWithClipboard() { + String clipboardData = Util.readTextFromClipboard(getActivity()); + + if (clipboardData == null) { + Toast.makeText(getActivity(), R.string.VerifyIdentityActivity_no_safety_numbers_to_compare_were_found_in_the_clipboard, Toast.LENGTH_LONG).show(); + return; + } + + String numericClipboardData = clipboardData.replaceAll("\\D", ""); + + if (TextUtils.isEmpty(numericClipboardData) || numericClipboardData.length() != 60) { + Toast.makeText(getActivity(), R.string.VerifyIdentityActivity_no_safety_numbers_to_compare_were_found_in_the_clipboard, Toast.LENGTH_LONG).show(); + return; + } + + if (fingerprint.getDisplayableFingerprint().getDisplayText().equals(numericClipboardData)) { + animateVerifiedSuccess(); + } else { + animateVerifiedFailure(); + } + } + private void setFingerprintViews(Fingerprint fingerprint) { String digits = fingerprint.getDisplayableFingerprint().getDisplayText(); int partSize = digits.length() / codes.length; diff --git a/src/org/thoughtcrime/securesms/util/Util.java b/src/org/thoughtcrime/securesms/util/Util.java index 6a776ba3f4..132d3ecc32 100644 --- a/src/org/thoughtcrime/securesms/util/Util.java +++ b/src/org/thoughtcrime/securesms/util/Util.java @@ -19,6 +19,8 @@ package org.thoughtcrime.securesms.util; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.ActivityManager; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Typeface; @@ -415,4 +417,34 @@ public class Util { public static float clamp(float value, float min, float max) { return Math.min(Math.max(value, min), max); } + + public static @Nullable String readTextFromClipboard(@NonNull Context context) { + if (VERSION.SDK_INT >= 11) { + ClipboardManager clipboardManager = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE); + + if (clipboardManager.hasPrimaryClip() && clipboardManager.getPrimaryClip().getItemCount() > 0) { + return clipboardManager.getPrimaryClip().getItemAt(0).getText().toString(); + } else { + return null; + } + } else { + android.text.ClipboardManager clipboardManager = (android.text.ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE); + + if (clipboardManager.hasText()) { + return clipboardManager.getText().toString(); + } else { + return null; + } + } + } + + public static void writeTextToClipboard(@NonNull Context context, @NonNull String text) { + if (VERSION.SDK_INT >= 11) { + ClipboardManager clipboardManager = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardManager.setPrimaryClip(ClipData.newPlainText("Safety numbers", text)); + } else { + android.text.ClipboardManager clipboardManager = (android.text.ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardManager.setText(text); + } + } }