From 6d6278002a8e40998120bdb1bdf02abafff3a24d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 20 Oct 2018 23:38:03 +0200 Subject: [PATCH] attempt to automatically detect pins in clipboard --- src/main/res/values/strings.xml | 1 + .../conversations/ui/VerifyActivity.java | 76 ++++- .../ui/util/PinEntryWrapper.java | 46 +++ .../res/layout/activity_enter_number.xml | 10 +- src/quick/res/layout/activity_verify.xml | 309 ++++++++++-------- 5 files changed, 295 insertions(+), 147 deletions(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 6391cf425..2ade6d2bf 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -764,4 +764,5 @@ Please enter the 6 digit pin below. Resend SMS back + Automatically pasted possible pin from clipboard. diff --git a/src/quick/java/eu/siacs/conversations/ui/VerifyActivity.java b/src/quick/java/eu/siacs/conversations/ui/VerifyActivity.java index 79ffde72f..f798d782d 100644 --- a/src/quick/java/eu/siacs/conversations/ui/VerifyActivity.java +++ b/src/quick/java/eu/siacs/conversations/ui/VerifyActivity.java @@ -1,12 +1,19 @@ package eu.siacs.conversations.ui; +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.ClipboardManager; +import android.content.Context; import android.content.Intent; import android.databinding.DataBindingUtil; import android.os.Bundle; +import android.support.design.widget.Snackbar; import android.support.v7.widget.Toolbar; import android.text.Html; import android.view.View; +import java.util.ArrayList; + import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ActivityVerifyBinding; import eu.siacs.conversations.entities.Account; @@ -14,25 +21,36 @@ import eu.siacs.conversations.ui.util.PinEntryWrapper; import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.PhoneNumberUtilWrapper; -public class VerifyActivity extends XmppActivity { +import static android.content.ClipDescription.MIMETYPE_TEXT_PLAIN; + +public class VerifyActivity extends XmppActivity implements ClipboardManager.OnPrimaryClipChangedListener { private ActivityVerifyBinding binding; private Account account; private PinEntryWrapper pinEntryWrapper; + private ClipboardManager clipboardManager; + private String pasted = null; + @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + String pin = savedInstanceState != null ? savedInstanceState.getString("pin") : null; + this.pasted = savedInstanceState != null ? savedInstanceState.getString("pasted") : null; this.binding = DataBindingUtil.setContentView(this, R.layout.activity_verify); setSupportActionBar((Toolbar) this.binding.toolbar); this.pinEntryWrapper = new PinEntryWrapper(binding.pinBox); + if (pin != null) { + this.pinEntryWrapper.setPin(pin); + } binding.back.setOnClickListener(this::onBackButton); + clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); } private void onBackButton(View view) { if (this.account != null) { xmppConnectionService.deleteAccount(account); - Intent intent = new Intent(this,EnterPhoneNumberActivity.class); + Intent intent = new Intent(this, EnterPhoneNumberActivity.class); startActivity(intent); finish(); } @@ -51,4 +69,58 @@ public class VerifyActivity extends XmppActivity { } this.binding.weHaveSent.setText(Html.fromHtml(getString(R.string.we_have_sent_you_an_sms, PhoneNumberUtilWrapper.prettyPhoneNumber(this, this.account.getJid())))); } + + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + savedInstanceState.putString("pin", this.pinEntryWrapper.getPin()); + if (this.pasted != null) { + savedInstanceState.putString("pasted", this.pasted); + } + super.onSaveInstanceState(savedInstanceState); + } + + @Override + public void onStart() { + super.onStart(); + clipboardManager.addPrimaryClipChangedListener(this); + } + + @Override + public void onStop() { + super.onStop(); + clipboardManager.removePrimaryClipChangedListener(this); + } + + @Override + public void onResume() { + super.onResume(); + if (pinEntryWrapper.isEmpty()) { + pastePinFromClipboard(); + } + } + + private void pastePinFromClipboard() { + final ClipDescription description = clipboardManager != null ? clipboardManager.getPrimaryClipDescription() : null; + if (description != null && description.hasMimeType(MIMETYPE_TEXT_PLAIN)) { + final ClipData primaryClip = clipboardManager.getPrimaryClip(); + if (primaryClip != null && primaryClip.getItemCount() > 0) { + final CharSequence clip = primaryClip.getItemAt(0).getText(); + if (PinEntryWrapper.isPin(clip) && !clip.toString().equals(this.pasted)) { + this.pasted = clip.toString(); + pinEntryWrapper.setPin(clip.toString()); + final Snackbar snackbar = Snackbar.make(binding.coordinator, R.string.possible_pin, Snackbar.LENGTH_LONG); + snackbar.setAction(R.string.undo, v -> pinEntryWrapper.clear()); + snackbar.show(); + } + } + } + } + + @Override + public void onPrimaryClipChanged() { + this.pasted = null; + if (pinEntryWrapper.isEmpty()) { + pastePinFromClipboard(); + } + } } diff --git a/src/quick/java/eu/siacs/conversations/ui/util/PinEntryWrapper.java b/src/quick/java/eu/siacs/conversations/ui/util/PinEntryWrapper.java index 8f22e2981..12d6e88ea 100644 --- a/src/quick/java/eu/siacs/conversations/ui/util/PinEntryWrapper.java +++ b/src/quick/java/eu/siacs/conversations/ui/util/PinEntryWrapper.java @@ -9,9 +9,13 @@ import android.widget.LinearLayout; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; + public class PinEntryWrapper { + private static Pattern PIN_STRING_PATTERN = Pattern.compile("^[0-9]{6}$"); + private final List digits = new ArrayList<>(); private final TextWatcher textWatcher = new TextWatcher() { @@ -68,6 +72,10 @@ public class PinEntryWrapper { return true; } } + if (current != 0) { + digits.get(0).requestFocus(); + return true; + } } } return false; @@ -90,4 +98,42 @@ public class PinEntryWrapper { } } + public String getPin() { + char[] chars = new char[digits.size()]; + for(int i = 0; i < chars.length; ++i) { + final String input = digits.get(i).getText().toString(); + chars[i] = input.length() != 1 ? ' ' : input.charAt(0); + } + return String.valueOf(chars); + } + + public void setPin(String pin) { + char[] chars = pin.toCharArray(); + for(int i = 0; i < digits.size(); ++i) { + if (i < chars.length) { + final Editable editable = digits.get(i).getText(); + editable.clear(); + editable.append(Character.isDigit(chars[i]) ? String.valueOf(chars[i]) : ""); + } + } + } + + public boolean isEmpty() { + for(EditText digit : digits) { + if (digit.getText().length() > 0) { + return false; + } + } + return true; + } + + public static boolean isPin(CharSequence pin) { + return pin != null && PIN_STRING_PATTERN.matcher(pin).matches(); + } + + public void clear() { + for(int i = digits.size() - 1; i >= 0; --i) { + digits.get(i).getText().clear(); + } + } } \ No newline at end of file diff --git a/src/quick/res/layout/activity_enter_number.xml b/src/quick/res/layout/activity_enter_number.xml index c91bb0a6a..aba47feb0 100644 --- a/src/quick/res/layout/activity_enter_number.xml +++ b/src/quick/res/layout/activity_enter_number.xml @@ -7,6 +7,10 @@ android:orientation="vertical"> + @@ -52,6 +57,7 @@ android:orientation="horizontal"> + diff --git a/src/quick/res/layout/activity_verify.xml b/src/quick/res/layout/activity_verify.xml index 578214d98..4fd66f4f2 100644 --- a/src/quick/res/layout/activity_verify.xml +++ b/src/quick/res/layout/activity_verify.xml @@ -9,155 +9,176 @@ - + + - + android:layout_height="match_parent"> - + - + - - + - - - - - - - - - - - - - -