Add copy and compare safety numbers from clipboard actions

// FREEBIE
master
Moxie Marlinspike 2016-11-14 19:50:29 -08:00
parent ca3337232b
commit b55a7ff5c0
6 changed files with 127 additions and 20 deletions

View File

@ -48,11 +48,17 @@
</FrameLayout>
<TableLayout android:layout_width="wrap_content"
<TableLayout android:id="@+id/number_table"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
android:layout_marginTop="5dp"
android:clickable="true"
android:focusable="true">
<TableRow android:gravity="center_horizontal"
android:clickable="false"
android:focusable="false">
<TableRow android:gravity="center_horizontal">
<TextView android:id="@+id/code_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_copy"
android:title="@string/verify_display_fragment_context_menu__copy_to_clipboard"/>
<item android:id="@+id/menu_compare"
android:title="@string/verify_display_fragment_context_menu__compare_with_clipboard"/>
</menu>

View File

@ -569,6 +569,7 @@
<string name="VerifyIdentityActivity_share_safety_numbers_via">Share safety numbers via...</string>
<string name="VerifyIdentityActivity_our_signal_safety_numbers">Our Signal safety numbers:</string>
<string name="VerifyIdentityActivity_no_app_to_share_to">It looks like you don\'t have any apps to share to.</string>
<string name="VerifyIdentityActivity_no_safety_numbers_to_compare_were_found_in_the_clipboard">No safety numbers to compare were found in the clipboard</string>
<!-- KeyExchangeInitiator -->
<string name="KeyExchangeInitiator_initiate_despite_existing_request_question">Initiate despite existing request?</string>
@ -1210,6 +1211,10 @@
<string name="text_secure_normal__invite_friends">Invite friends</string>
<string name="text_secure_normal__help">Help</string>
<!-- verify_display_fragment -->
<string name="verify_display_fragment_context_menu__copy_to_clipboard">Copy to clipboard</string>
<string name="verify_display_fragment_context_menu__compare_with_clipboard">Compare with clipboard</string>
<!-- reminder_header -->
<string name="reminder_header_outdated_build">Your version of Signal is outdated</string>
<plurals name="reminder_header_outdated_build_details">
@ -1268,7 +1273,6 @@
<string name="transport_selection_list_item__transport_icon">Transport icon</string>
<!-- EOF -->
</resources>

View File

@ -231,6 +231,8 @@
<item name="android:fontFamily">monospace</item>
<item name="android:typeface">monospace</item>
<item name="android:textSize">17sp</item>
<item name="android:clickable">false</item>
<item name="android:focusable">false</item>
</style>
</resources>

View File

@ -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;

View File

@ -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);
}
}
}