diff options
Diffstat (limited to 'OpenKeychain')
10 files changed, 394 insertions, 1207 deletions
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index b6f8f21a0..1df95bc20 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -50,6 +50,7 @@ dependencies { compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.0' compile 'org.ocpsoft.prettytime:prettytime:4.0.1.Final' compile 'com.splitwise:tokenautocomplete:2.0.2@aar' + compile 'com.github.pinball83:masked-edittext:1.0.3' compile 'se.emilsjolander:stickylistheaders:2.7.0' compile 'org.sufficientlysecure:html-textview:1.3' compile 'org.sufficientlysecure:donations:2.4' @@ -87,47 +88,48 @@ dependencies { // Comment out the libs referenced as git submodules! dependencyVerification { verify = [ - 'com.android.support:support-v4:5c7dceb6c824089fe80f502e5206264048ef8bffa4e8ddeab180b81723e79b7f', - 'com.android.support:appcompat-v7:0a8762214382b7e8d4b989b4ac10b5c846b957d767ccb7bccbc6be5afa885a82', - 'com.android.support:design:41a9cd75ca78f25df5f573db7cedf8bb66beae00c330943923ba9f3e2051736d', - 'com.android.support:recyclerview-v7:7606373da0931a1e62588335465a0e390cd676c98117edab29220317495faefd', - 'com.android.support:cardview-v7:5a5bc04a278662bfafdea5b11b2108a4b354dca6c68958b312f6f45cc5fe2e38', - 'com.eftimoff:android-patternview:594dde382fb9a445ef0c92d614f6f127727ce699f124de8167929e10f298bf8b', - 'com.journeyapps:zxing-android-embedded:90840a4457e68962fdfb74f691c6a736be7596291001045241901f1f0e6db2ac', - 'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259', - 'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311', - 'com.getbase:floatingactionbutton:3edefa511aac4d90794c7b0496aca59cff2eee1e32679247b4f85acbeee05240', - 'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13', - 'org.ocpsoft.prettytime:prettytime:ef7098d973ae78b57d1a22dc37d3b8a771bf030301300e24055d676b6cdc5e75', - 'com.splitwise:tokenautocomplete:2fc238424130b42155b5f2e39799a90bbbd13b148850afbe534ab08bb913c7f7', - 'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb', - 'org.sufficientlysecure:html-textview:39048e35894e582adada388e6c00631803283f8defed8e07ad58a5f284f272ee', - 'com.nispok:snackbar:46b5eb9d630d329e13c2ce00ee9fb115ffb66c23c72cff32ee97eedd76824c6f', - 'org.sufficientlysecure:donations:96f8197bab26dfe41900d824f10f8f1914519cd62eedb77bdac5b223eccdf0a6', - 'com.squareup.okhttp:okhttp-urlconnection:8dce03792fd7b5f089dc4fc0fdcecbbe50ae6cca21cb08a787a3b902a9914111', - 'com.squareup.okhttp:okhttp:8df336e3e93b22ba8c05da5d94caf968950db845869c7ca16ed682e065135aa8', - 'org.apache.james:apache-mime4j-dom:7e6b06ee164a1c21b7e477249ea0b74a18fddce44764e5764085f58dd8c34633', - 'org.apache.james:apache-mime4j-core:4d7434c68f94b81a253c12f28e6bbb4d6239c361d6086a46e22e594bb43ac660', - 'com.cocosw:bottomsheet:40d2187c9cdaf224acbf876abc138cd9d4a293ef89091982ecf2492c8fcd186b', - 'org.thoughtcrime.ssl.pinning:AndroidPinning:afa1d74e699257fa75cb109ff29bac50726ef269c6e306bdeffe8223cee06ef4', - 'com.mikepenz:materialize:2457dbe0b874a422c0a21bc6716cf5af1d5a8d39387857ff7c20855ab5543bf8', - 'com.mikepenz:materialdrawer:4e2644f454cc2ce48b956536d3339957c3f592adb2e0b6dad72d477da29f7677', - 'com.mikepenz:google-material-typeface:48b2712de87d542e9b050846e9f602238a367f38e2d5e8ea4557c5b12adfcbec', - 'com.mikepenz:iconics-core:d2495547db9d881168b1b502b1934f6a000ed5086c6c6a7114f3bbcbbb7ec306', - 'com.mikepenz:community-material-typeface:990acfcfb892a733d36748fe29176bd61dd5ab34bc8ca1c591200e639d955b99', - 'com.mikepenz:fontawesome-typeface:69cb09934a83bac607e78a29459868d537f766224b4a65a042d1f84c98c7b05d', - 'com.fidesmo:nordpol-core:3de58e850a00bba5b4d3a604d1399bcd89f695ea191ec0b03a57222e18062d15', - 'com.fidesmo:nordpol-android:56f43fe2b1676817bcb4085926de14a08282ef6729c855c198d81aec62b20d65', -// 'OpenKeychain.extern.bouncycastle:core:b22dfb37e09fb520683dd0ba089351787560a75b59b60822143f633ec984cab5', -// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:8a53012b9df6d62174ebdc11e0ab56700501a915930db5c12e32d565f136fc06', -// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:9263330c00497b7bb70502160f50c8396228129376f48f4f5656d28360a2edac', -// 'OpenKeychain.extern.bouncycastle:prov:2d93a52e1b519995b18c0a92a1e59a2773d67d9b466a9cce6af5202a66502577', -// 'OpenKeychain.extern.bouncycastle:pg:1397025acf36be36d329c0345b136af776be82fe5d6dad70cc06db09d2f02201', -// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:989fcc0eba663489a41aa166f6bb39f21271d980faddea5f06ab75339e792d10', - 'com.android.support:support-annotations:f347a35b9748a4103b39a6714a77e2100f488d623fd6268e259c177b200e9d82', -// 'OpenKeychain.extern:minidns:109d5851ab351d7628ed62a0ed96b40598952424e56657c17debbeb4a704f0ce', -// 'OpenKeychain.extern.KeybaseLib:Lib:c5b1567ff781c311240e83f865c4ba76ae435eb00994529b8364371abf0d76de', - 'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266', + 'com.android.support:support-v4:5c7dceb6c824089fe80f502e5206264048ef8bffa4e8ddeab180b81723e79b7f', + 'com.android.support:appcompat-v7:0a8762214382b7e8d4b989b4ac10b5c846b957d767ccb7bccbc6be5afa885a82', + 'com.android.support:design:41a9cd75ca78f25df5f573db7cedf8bb66beae00c330943923ba9f3e2051736d', + 'com.android.support:recyclerview-v7:7606373da0931a1e62588335465a0e390cd676c98117edab29220317495faefd', + 'com.android.support:cardview-v7:5a5bc04a278662bfafdea5b11b2108a4b354dca6c68958b312f6f45cc5fe2e38', + 'com.eftimoff:android-patternview:594dde382fb9a445ef0c92d614f6f127727ce699f124de8167929e10f298bf8b', + 'com.journeyapps:zxing-android-embedded:90840a4457e68962fdfb74f691c6a736be7596291001045241901f1f0e6db2ac', + 'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259', + 'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311', + 'com.getbase:floatingactionbutton:3edefa511aac4d90794c7b0496aca59cff2eee1e32679247b4f85acbeee05240', + 'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13', + 'org.ocpsoft.prettytime:prettytime:ef7098d973ae78b57d1a22dc37d3b8a771bf030301300e24055d676b6cdc5e75', + 'com.splitwise:tokenautocomplete:2fc238424130b42155b5f2e39799a90bbbd13b148850afbe534ab08bb913c7f7', + 'com.github.pinball83:masked-edittext:b1913d86482c7066ebb7831696773ac131865dc441cf8a3fc41d3b7d5691724e', + 'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb', + 'org.sufficientlysecure:donations:96f8197bab26dfe41900d824f10f8f1914519cd62eedb77bdac5b223eccdf0a6', + 'org.sufficientlysecure:html-textview:39048e35894e582adada388e6c00631803283f8defed8e07ad58a5f284f272ee', + 'com.squareup.okhttp:okhttp:8df336e3e93b22ba8c05da5d94caf968950db845869c7ca16ed682e065135aa8', + 'com.nispok:snackbar:46b5eb9d630d329e13c2ce00ee9fb115ffb66c23c72cff32ee97eedd76824c6f', + 'org.apache.james:apache-mime4j-core:4d7434c68f94b81a253c12f28e6bbb4d6239c361d6086a46e22e594bb43ac660', + 'com.squareup.okhttp:okhttp-urlconnection:8dce03792fd7b5f089dc4fc0fdcecbbe50ae6cca21cb08a787a3b902a9914111', + 'org.thoughtcrime.ssl.pinning:AndroidPinning:afa1d74e699257fa75cb109ff29bac50726ef269c6e306bdeffe8223cee06ef4', + 'org.apache.james:apache-mime4j-dom:7e6b06ee164a1c21b7e477249ea0b74a18fddce44764e5764085f58dd8c34633', + 'com.mikepenz:materialdrawer:4e2644f454cc2ce48b956536d3339957c3f592adb2e0b6dad72d477da29f7677', + 'com.cocosw:bottomsheet:40d2187c9cdaf224acbf876abc138cd9d4a293ef89091982ecf2492c8fcd186b', + 'com.mikepenz:iconics-core:d2495547db9d881168b1b502b1934f6a000ed5086c6c6a7114f3bbcbbb7ec306', + 'com.mikepenz:materialize:2457dbe0b874a422c0a21bc6716cf5af1d5a8d39387857ff7c20855ab5543bf8', + 'com.mikepenz:fontawesome-typeface:69cb09934a83bac607e78a29459868d537f766224b4a65a042d1f84c98c7b05d', + 'com.mikepenz:google-material-typeface:48b2712de87d542e9b050846e9f602238a367f38e2d5e8ea4557c5b12adfcbec', + 'com.fidesmo:nordpol-android:56f43fe2b1676817bcb4085926de14a08282ef6729c855c198d81aec62b20d65', + 'com.mikepenz:community-material-typeface:990acfcfb892a733d36748fe29176bd61dd5ab34bc8ca1c591200e639d955b99', +// 'OpenKeychain.extern.bouncycastle:core:b22dfb37e09fb520683dd0ba089351787560a75b59b60822143f633ec984cab5', +// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:8a53012b9df6d62174ebdc11e0ab56700501a915930db5c12e32d565f136fc06', +// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:9263330c00497b7bb70502160f50c8396228129376f48f4f5656d28360a2edac', +// 'OpenKeychain.extern.bouncycastle:prov:2d93a52e1b519995b18c0a92a1e59a2773d67d9b466a9cce6af5202a66502577', +// 'OpenKeychain.extern.bouncycastle:pg:1397025acf36be36d329c0345b136af776be82fe5d6dad70cc06db09d2f02201', +// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:989fcc0eba663489a41aa166f6bb39f21271d980faddea5f06ab75339e792d10', + 'com.android.support:support-annotations:f347a35b9748a4103b39a6714a77e2100f488d623fd6268e259c177b200e9d82', +// 'OpenKeychain.extern:minidns:109d5851ab351d7628ed62a0ed96b40598952424e56657c17debbeb4a704f0ce', +// 'OpenKeychain.extern.KeybaseLib:Lib:c5b1567ff781c311240e83f865c4ba76ae435eb00994529b8364371abf0d76de', + 'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266', + 'com.fidesmo:nordpol-core:3de58e850a00bba5b4d3a604d1399bcd89f695ea191ec0b03a57222e18062d15', ] } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java index b6f102593..c4755c7c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java @@ -278,7 +278,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp ArmorHeaders armorHeaders = parseArmorHeaders(in, log, indent); String charset = armorHeaders.charset; boolean useBackupCode = false; - if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 1) { + if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 2) { useBackupCode = true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index f1d4d1272..009876045 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -152,7 +152,7 @@ public class PgpSignEncryptOperation extends BaseOperation { } // add proprietary header to indicate that this is a key backup if (input.isAddBackupHeader()) { - armorOut.setHeader("BackupVersion", "1"); + armorOut.setHeader("BackupVersion", "2"); } out = armorOut; } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java index 2d2e43e3b..a9dfaa2c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * Copyright (C) 2016 Dominik Schürmann <dominik@dominikschuermann.de> * * 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 @@ -40,7 +41,7 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager.OnBackStackChangedListener; import android.text.Editable; -import android.text.TextUtils; +import android.text.InputType; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.Menu; @@ -50,9 +51,12 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; +import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; +import com.github.pinball83.maskededittext.MaskedEditText; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ExportResult; @@ -79,12 +83,20 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar public static final int REQUEST_SAVE = 1; public static final String ARG_BACK_STACK = "back_stack"; + // https://github.com/open-keychain/open-keychain/wiki/Backups + // excludes 0 and O + private static final char[] mBackupCodeAlphabet = + new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + // argument variables private boolean mExportSecret; private long[] mMasterKeyIds; String mBackupCode; - private EditText[] mCodeEditText; + private MaskedEditText mCodeEditText; + private ToolableViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator; private Integer mBackStackLevel; @@ -96,7 +108,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar BackupCodeFragment frag = new BackupCodeFragment(); Bundle args = new Bundle(); - args.putString(ARG_BACKUP_CODE, generateRandomCode()); + args.putString(ARG_BACKUP_CODE, generateRandomBackupCode()); args.putLongArray(ARG_MASTER_KEY_IDS, masterKeyIds); args.putBoolean(ARG_EXPORT_SECRET, exportSecret); frag.setArguments(args); @@ -132,14 +144,11 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar if (Constants.DEBUG && item.getItemId() == R.id.debug_accept_any_log) { boolean newCheckedState = !item.isChecked(); item.setChecked(newCheckedState); - if (newCheckedState && TextUtils.isEmpty(mCodeEditText[0].getText())) { - mCodeEditText[0].setText("ABCDEF"); - mCodeEditText[1].setText("GHIJKL"); - mCodeEditText[2].setText("MNOPQR"); - mCodeEditText[3].setText("STUVW"); + mDebugModeAcceptAnyCode = newCheckedState; + if (newCheckedState) { + mCodeEditText.setText("ABCD-EFGH-IJKL-MNOP-QRST-UVWX"); Notify.create(getActivity(), "Actual backup code is all 'A's", Style.WARN).show(); } - mDebugModeAcceptAnyCode = newCheckedState; return true; } return super.onOptionsItemSelected(item); @@ -161,9 +170,11 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar mTitleAnimator.setDisplayedChild(1, animate); mStatusAnimator.setDisplayedChild(1, animate); mCodeFieldsAnimator.setDisplayedChild(1, animate); - for (EditText editText : mCodeEditText) { - editText.setText(""); - } + // use non-breaking spaces to enlarge the empty EditText appropriately + String empty = "\u00a0\u00a0\u00a0\u00a0-\u00a0\u00a0\u00a0\u00a0" + + "-\u00a0\u00a0\u00a0\u00a0-\u00a0\u00a0\u00a0\u00a0" + + "-\u00a0\u00a0\u00a0\u00a0-\u00a0\u00a0\u00a0\u00a0"; + mCodeEditText.setText(empty); pushBackStackEntry(); @@ -177,7 +188,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar hideKeyboard(); if (animate) { - @ColorInt int black = mCodeEditText[0].getCurrentTextColor(); + @ColorInt int black = mCodeEditText.getCurrentTextColor(); @ColorInt int red = getResources().getColor(R.color.android_red_dark); animateFlashText(mCodeEditText, black, red, false); } @@ -192,18 +203,14 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar hideKeyboard(); - for (EditText editText : mCodeEditText) { - editText.setEnabled(false); - } + mCodeEditText.setEnabled(false); @ColorInt int green = getResources().getColor(R.color.android_green_dark); if (animate) { - @ColorInt int black = mCodeEditText[0].getCurrentTextColor(); + @ColorInt int black = mCodeEditText.getCurrentTextColor(); animateFlashText(mCodeEditText, black, green, true); } else { - for (TextView textView : mCodeEditText) { - textView.setTextColor(green); - } + mCodeEditText.setTextColor(green); } popBackStackNoAction(); @@ -226,34 +233,22 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar mMasterKeyIds = args.getLongArray(ARG_MASTER_KEY_IDS); mExportSecret = args.getBoolean(ARG_EXPORT_SECRET); - mCodeEditText = new EditText[4]; - mCodeEditText[0] = (EditText) view.findViewById(R.id.backup_code_1); - mCodeEditText[1] = (EditText) view.findViewById(R.id.backup_code_2); - mCodeEditText[2] = (EditText) view.findViewById(R.id.backup_code_3); - mCodeEditText[3] = (EditText) view.findViewById(R.id.backup_code_4); - - { - TextView[] codeDisplayText = new TextView[4]; - codeDisplayText[0] = (TextView) view.findViewById(R.id.backup_code_display_1); - codeDisplayText[1] = (TextView) view.findViewById(R.id.backup_code_display_2); - codeDisplayText[2] = (TextView) view.findViewById(R.id.backup_code_display_3); - codeDisplayText[3] = (TextView) view.findViewById(R.id.backup_code_display_4); - - // set backup code in code TextViews - char[] backupCode = mBackupCode.toCharArray(); - for (int i = 0; i < codeDisplayText.length; i++) { - codeDisplayText[i].setText(backupCode, i * 7, 6); - } + // NOTE: order of these method calls matter, see setupAutomaticLinebreak() + mCodeEditText = (MaskedEditText) view.findViewById(R.id.backup_code_input); + mCodeEditText.setInputType( + InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS); + setupAutomaticLinebreak(mCodeEditText); + mCodeEditText.setImeOptions(EditorInfo.IME_ACTION_DONE); + setupEditTextSuccessListener(mCodeEditText); - // set background to null in TextViews - this will retain padding from EditText style! - for (TextView textView : codeDisplayText) { - // noinspection deprecation, setBackground(Drawable) is API level >=16 - textView.setBackgroundDrawable(null); - } - } + TextView codeDisplayText = (TextView) view.findViewById(R.id.backup_code_display); + setupAutomaticLinebreak(codeDisplayText); - setupEditTextFocusNext(mCodeEditText); - setupEditTextSuccessListener(mCodeEditText); + // set background to null in TextViews - this will retain padding from EditText style! + // noinspection deprecation, setBackground(Drawable) is API level >=16 + codeDisplayText.setBackgroundDrawable(null); + + codeDisplayText.setText(mBackupCode); mStatusAnimator = (ToolableViewAnimator) view.findViewById(R.id.status_animator); mTitleAnimator = (ToolableViewAnimator) view.findViewById(R.id.title_animator); @@ -331,76 +326,67 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar outState.putInt(ARG_BACK_STACK, mBackStackLevel == null ? -1 : mBackStackLevel); } - private void setupEditTextSuccessListener(final EditText[] backupCodes) { - for (EditText backupCode : backupCodes) { + /** + * Automatic line break with max 6 lines for smaller displays + * <p/> + * NOTE: I was not able to get this behaviour using XML! + * Looks like the order of these method calls matter, see http://stackoverflow.com/a/11171307 + */ + private void setupAutomaticLinebreak(TextView textview) { + textview.setSingleLine(true); + textview.setMaxLines(6); + textview.setHorizontallyScrolling(false); + } - backupCode.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { + private void setupEditTextSuccessListener(final MaskedEditText backupCode) { + backupCode.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 6) { - throw new AssertionError("max length of each field is 6!"); - } - - boolean inInputState = mCurrentState == BackupCodeState.STATE_INPUT - || mCurrentState == BackupCodeState.STATE_INPUT_ERROR; - boolean partIsComplete = s.length() == 6; - if (!inInputState || !partIsComplete) { - return; - } - - checkIfCodeIsCorrect(); + @Override + public void afterTextChanged(Editable s) { + boolean inInputState = mCurrentState == BackupCodeState.STATE_INPUT + || mCurrentState == BackupCodeState.STATE_INPUT_ERROR; + boolean partIsComplete = (backupCode.getText().toString().indexOf(' ') == -1) + && (backupCode.getText().toString().indexOf('\u00a0') == -1); + if (!inInputState || !partIsComplete) { + return; } - }); - } + checkIfCodeIsCorrect(backupCode); + } + }); } - private void checkIfCodeIsCorrect() { + private void checkIfCodeIsCorrect(EditText backupCode) { if (Constants.DEBUG && mDebugModeAcceptAnyCode) { switchState(BackupCodeState.STATE_OK, true); return; } - StringBuilder backupCodeInput = new StringBuilder(26); - for (EditText editText : mCodeEditText) { - if (editText.getText().length() < 6) { - return; - } - backupCodeInput.append(editText.getText()); - backupCodeInput.append('-'); - } - backupCodeInput.deleteCharAt(backupCodeInput.length() - 1); - - // if they don't match, do nothing - if (backupCodeInput.toString().equals(mBackupCode)) { + if (backupCode.toString().equals(mBackupCode)) { switchState(BackupCodeState.STATE_OK, true); return; } switchState(BackupCodeState.STATE_INPUT_ERROR, true); - } private static void animateFlashText( - final TextView[] textViews, int color1, int color2, boolean staySecondColor) { + final TextView textView, int color1, int color2, boolean staySecondColor) { ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), color1, color2); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animator) { - for (TextView textView : textViews) { - textView.setTextColor((Integer) animator.getAnimatedValue()); - } + textView.setTextColor((Integer) animator.getAnimatedValue()); } }); anim.setRepeatMode(ValueAnimator.REVERSE); @@ -411,34 +397,6 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar } - private static void setupEditTextFocusNext(final EditText[] backupCodes) { - for (int i = 0; i < backupCodes.length - 1; i++) { - - final int next = i + 1; - - backupCodes[i].addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - boolean inserting = before < count; - boolean cursorAtEnd = (start + count) == 6; - - if (inserting && cursorAtEnd) { - backupCodes[next].requestFocus(); - } - } - - @Override - public void afterTextChanged(Editable s) { - } - }); - - } - } - private void pushBackStackEntry() { if (mBackStackLevel != null) { return; @@ -557,7 +515,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar public BackupKeyringParcel createOperationInput() { Passphrase passphrase = new Passphrase(mBackupCode); if (Constants.DEBUG && mDebugModeAcceptAnyCode) { - passphrase = new Passphrase("AAAAAA-AAAAAA-AAAAAA-AAAAAA"); + passphrase = new Passphrase("AAAA-AAAA-AAAA-AAAA-AAAA-AAAA"); } return new BackupKeyringParcel(passphrase, mMasterKeyIds, mExportSecret, mCachedBackupUri); } @@ -578,22 +536,26 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar mCachedBackupUri = null; } + /** + * Generate backup code using format defined in + * https://github.com/open-keychain/open-keychain/wiki/Backups + */ @NonNull - private static String generateRandomCode() { + private static String generateRandomBackupCode() { Random r = new SecureRandom(); - // simple generation of a 20 character backup code + // simple generation of a 24 character backup code StringBuilder code = new StringBuilder(28); for (int i = 0; i < 24; i++) { - if (i == 6 || i == 12 || i == 18) { + if (i == 4 || i == 8 || i == 12 || i == 16 || i == 20) { code.append('-'); } - code.append((char) ('A' + r.nextInt(26))); + + code.append(mBackupCodeAlphabet[r.nextInt(mBackupCodeAlphabet.length)]); } return code.toString(); - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 88616117f..f1edaccef 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014-2016 Dominik Schürmann <dominik@dominikschuermann.de> * * 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 @@ -46,6 +46,8 @@ import android.widget.TextView; import android.widget.Toast; import android.widget.ViewAnimator; +import com.github.pinball83.maskededittext.MaskedEditText; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; @@ -158,7 +160,7 @@ public class PassphraseDialogActivity extends FragmentActivity { public static class PassphraseDialogFragment extends DialogFragment implements TextView.OnEditorActionListener { private EditText mPassphraseEditText; private TextView mPassphraseText; - private EditText[] mBackupCodeEditText; + private MaskedEditText mBackupCodeEditText; private boolean mIsCancelled = false; private RequiredInputParcel mRequiredInput; @@ -185,12 +187,13 @@ public class PassphraseDialogActivity extends FragmentActivity { View view = inflater.inflate(R.layout.passphrase_dialog_backup_code, null); alert.setView(view); - mBackupCodeEditText = new EditText[4]; - mBackupCodeEditText[0] = (EditText) view.findViewById(R.id.backup_code_1); - mBackupCodeEditText[1] = (EditText) view.findViewById(R.id.backup_code_2); - mBackupCodeEditText[2] = (EditText) view.findViewById(R.id.backup_code_3); - mBackupCodeEditText[3] = (EditText) view.findViewById(R.id.backup_code_4); - setupEditTextFocusNext(mBackupCodeEditText); + mBackupCodeEditText = (MaskedEditText) view.findViewById(R.id.backup_code); + // NOTE: order of these method calls matter, see setupAutomaticLinebreak() + mBackupCodeEditText.setInputType( + InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS); + setupAutomaticLinebreak(mBackupCodeEditText); + mBackupCodeEditText.setImeActionLabel(getString(android.R.string.ok), EditorInfo.IME_ACTION_DONE); + mBackupCodeEditText.setOnEditorActionListener(this); AlertDialog dialog = alert.create(); dialog.setButton(DialogInterface.BUTTON_POSITIVE, @@ -324,32 +327,16 @@ public class PassphraseDialogActivity extends FragmentActivity { return dialog; } - private static void setupEditTextFocusNext(final EditText[] backupCodes) { - for (int i = 0; i < backupCodes.length - 1; i++) { - - final int next = i + 1; - - backupCodes[i].addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - boolean inserting = before < count; - boolean cursorAtEnd = (start + count) == 6; - - if (inserting && cursorAtEnd) { - backupCodes[next].requestFocus(); - } - } - - @Override - public void afterTextChanged(Editable s) { - } - }); - - } + /** + * Automatic line break with max 6 lines for smaller displays + * <p/> + * NOTE: I was not able to get this behaviour using XML! + * Looks like the order of these method calls matter, see http://stackoverflow.com/a/11171307 + */ + private void setupAutomaticLinebreak(TextView textview) { + textview.setSingleLine(true); + textview.setMaxLines(6); + textview.setHorizontallyScrolling(false); } @Override @@ -363,17 +350,8 @@ public class PassphraseDialogActivity extends FragmentActivity { public void onClick(View v) { if (mRequiredInput.mType == RequiredInputType.BACKUP_CODE) { - StringBuilder backupCodeInput = new StringBuilder(26); - for (EditText editText : mBackupCodeEditText) { - if (editText.getText().length() < 6) { - return; - } - backupCodeInput.append(editText.getText()); - backupCodeInput.append('-'); - } - backupCodeInput.deleteCharAt(backupCodeInput.length() - 1); - - Passphrase passphrase = new Passphrase(backupCodeInput.toString()); + Passphrase passphrase = + new Passphrase(mBackupCodeEditText.getText().toString()); finishCaching(passphrase); return; diff --git a/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml index d01fd10ec..0a4f97d53 100644 --- a/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml +++ b/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:custom="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" @@ -56,200 +57,39 @@ android:outAnimation="@anim/fade_out" custom:initialView="1"> - <LinearLayout + <TextView + android:id="@+id/backup_code_display" + style="@android:style/Widget.EditText" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <TextView - android:id="@+id/backup_code_display_1" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="ABCDEF" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_2" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="GHIJKL" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_3" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="MNOPQR" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_4" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:singleLine="true" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="STUVWX" /> - - </LinearLayout> - - <LinearLayout + android:layout_gravity="center_horizontal" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:clickable="false" + android:focusable="false" + android:singleLine="true" + android:textSize="18dp" + android:textStyle="bold" + android:typeface="monospace" + tools:ignore="SpUsage" + tools:text="AAAA-AAAA-AAAA-AAAA-AAAA-AAAA" /> + + <com.github.pinball83.maskededittext.MaskedEditText + android:id="@+id/backup_code_input" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <!-- - The most reliable way to correctly size these I found was to put a transparent hint on them. - Theoretically, this should be what the android:ems attribute is for - didn't work for me. - --> - <EditText - android:id="@+id/backup_code_1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_3" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_4" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - </LinearLayout> + android:layout_gravity="center_horizontal" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:textSize="18dp" + android:textStyle="bold" + android:typeface="monospace" + app:deleteChar="\u00a0" + app:mask="****-****-****-****-****-****" + app:maskIconColor="@color/colorPrimary" + app:notMaskedSymbol="*" + app:replacementChar="\u00a0" + tools:ignore="SpUsage" /> </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> diff --git a/OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml deleted file mode 100644 index fc3816352..000000000 --- a/OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml +++ /dev/null @@ -1,359 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:custom="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingTop="50dp"> - - <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator - android:id="@+id/title_animator" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:inAnimation="@anim/fade_in" - android:outAnimation="@anim/fade_out" - custom:initialView="0"> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" - android:padding="10dp" - android:text="@string/backup_code_explanation" /> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" - android:padding="10dp" - android:text="@string/backup_code_enter" /> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" - android:padding="10dp" - android:text="@string/backup_code_ok" /> - - </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> - - <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator - android:id="@+id/code_animator" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="15dp" - android:layout_marginTop="15dp" - android:inAnimation="@anim/fade_in" - android:outAnimation="@anim/fade_out" - custom:initialView="0"> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <TextView - android:id="@+id/backup_code_display_1" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="ABCDEF" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_2" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="GHIJKL" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_3" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="MNOPQR" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_4" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:singleLine="true" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="STUVWX" /> - - </LinearLayout> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <!-- - The most reliable way to correctly size these I found was to put a transparent hint on them. - Theoretically, this should be what the android:ems attribute is for - didn't work for me. - --> - <EditText - android:id="@+id/backup_code_1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_3" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_4" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="16dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - </LinearLayout> - - </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> - - <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator - android:id="@+id/status_animator" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:inAnimation="@anim/fade_in_delayed" - android:outAnimation="@anim/fade_out" - custom:initialView="2"> - - <Button - android:id="@+id/button_backup_input" - style="?android:buttonBarButtonStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_margin="10dp" - android:drawableLeft="@drawable/ic_mode_edit_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_code_wrotedown" /> - - <Space - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:orientation="vertical"> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:text="@string/backup_code_wrong" /> - - <Button - android:id="@+id/button_backup_back" - style="?android:buttonBarButtonStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_margin="10dp" - android:drawableLeft="@drawable/ic_repeat_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_backup_back" /> - - </LinearLayout> - - <LinearLayout - style="?android:buttonBarStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:orientation="vertical"> - - <LinearLayout - style="?android:buttonBarStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <Button - android:id="@+id/button_backup_share" - style="?android:buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:layout_weight="1" - android:drawableLeft="@drawable/ic_share_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_backup_share" /> - - <Button - android:id="@+id/button_backup_save" - style="?android:buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:layout_weight="1" - android:drawableLeft="@drawable/ic_save_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_backup_save" /> - - - </LinearLayout> - - <Button - android:id="@+id/button_faq" - style="?android:buttonBarButtonStyle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:text="@string/how_to_import" /> - </LinearLayout> - - </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> - -</LinearLayout> diff --git a/OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml deleted file mode 100644 index 39f4c9380..000000000 --- a/OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml +++ /dev/null @@ -1,359 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:custom="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingTop="50dp"> - - <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator - android:id="@+id/title_animator" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:inAnimation="@anim/fade_in" - android:outAnimation="@anim/fade_out" - custom:initialView="0"> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" - android:padding="10dp" - android:text="@string/backup_code_explanation" /> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" - android:padding="10dp" - android:text="@string/backup_code_enter" /> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" - android:padding="10dp" - android:text="@string/backup_code_ok" /> - - </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> - - <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator - android:id="@+id/code_animator" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="15dp" - android:layout_marginTop="15dp" - android:inAnimation="@anim/fade_in" - android:outAnimation="@anim/fade_out" - custom:initialView="0"> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <TextView - android:id="@+id/backup_code_display_1" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="ABCDEF" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_2" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="GHIJKL" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_3" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="MNOPQR" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:id="@+id/backup_code_display_4" - style="@android:style/Widget.EditText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:clickable="false" - android:focusable="false" - android:singleLine="true" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="SpUsage" - tools:text="STUVWX" /> - - </LinearLayout> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <!-- - The most reliable way to correctly size these I found was to put a transparent hint on them. - Theoretically, this should be what the android:ems attribute is for - didn't work for me. - --> - <EditText - android:id="@+id/backup_code_1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_3" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_4" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="18dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - </LinearLayout> - - </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> - - <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator - android:id="@+id/status_animator" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:inAnimation="@anim/fade_in_delayed" - android:outAnimation="@anim/fade_out" - custom:initialView="2"> - - <Button - android:id="@+id/button_backup_input" - style="?android:buttonBarButtonStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_margin="10dp" - android:drawableLeft="@drawable/ic_mode_edit_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_code_wrotedown" /> - - <Space - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:orientation="vertical"> - - <TextView - style="?android:textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:text="@string/backup_code_wrong" /> - - <Button - android:id="@+id/button_backup_back" - style="?android:buttonBarButtonStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_margin="10dp" - android:drawableLeft="@drawable/ic_repeat_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_backup_back" /> - - </LinearLayout> - - <LinearLayout - style="?android:buttonBarStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:orientation="vertical"> - - <LinearLayout - style="?android:buttonBarStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"> - - <Button - android:id="@+id/button_backup_share" - style="?android:buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:layout_weight="1" - android:drawableLeft="@drawable/ic_share_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_backup_share" /> - - <Button - android:id="@+id/button_backup_save" - style="?android:buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:layout_weight="1" - android:drawableLeft="@drawable/ic_save_grey_24dp" - android:drawablePadding="8dp" - android:padding="12dp" - android:text="@string/btn_backup_save" /> - - - </LinearLayout> - - <Button - android:id="@+id/button_faq" - style="?android:buttonBarButtonStyle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:text="@string/how_to_import" /> - </LinearLayout> - - </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> - -</LinearLayout> diff --git a/OpenKeychain/src/main/res/layout/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout/backup_code_fragment.xml new file mode 100644 index 000000000..330f18d1c --- /dev/null +++ b/OpenKeychain/src/main/res/layout/backup_code_fragment.xml @@ -0,0 +1,199 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:custom="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingTop="20dp"> + + <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator + android:id="@+id/title_animator" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:inAnimation="@anim/fade_in" + android:outAnimation="@anim/fade_out" + custom:initialView="0"> + + <TextView + style="?android:textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:padding="10dp" + android:text="@string/backup_code_explanation" /> + + <TextView + style="?android:textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:padding="10dp" + android:text="@string/backup_code_enter" /> + + <TextView + style="?android:textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:padding="10dp" + android:text="@string/backup_code_ok" /> + + </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> + + <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator + android:id="@+id/code_animator" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginBottom="15dp" + android:layout_marginTop="15dp" + android:inAnimation="@anim/fade_in" + android:outAnimation="@anim/fade_out" + custom:initialView="1"> + + <TextView + android:id="@+id/backup_code_display" + style="@android:style/Widget.EditText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:clickable="false" + android:focusable="false" + android:singleLine="true" + android:textSize="18dp" + android:textStyle="bold" + android:typeface="monospace" + tools:ignore="SpUsage" + tools:text="AAAA-AAAA-AAAA-AAAA-AAAA-AAAA" /> + + <com.github.pinball83.maskededittext.MaskedEditText + android:id="@+id/backup_code_input" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:textSize="18dp" + android:textStyle="bold" + android:typeface="monospace" + app:deleteChar="\u00a0" + app:mask="****-****-****-****-****-****" + app:maskIconColor="@color/colorPrimary" + app:notMaskedSymbol="*" + app:replacementChar="\u00a0" + tools:ignore="SpUsage" /> + + </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> + + <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator + android:id="@+id/status_animator" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:inAnimation="@anim/fade_in_delayed" + android:outAnimation="@anim/fade_out" + custom:initialView="2"> + + <Button + android:id="@+id/button_backup_input" + style="?android:buttonBarButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_margin="10dp" + android:drawableLeft="@drawable/ic_mode_edit_grey_24dp" + android:drawablePadding="8dp" + android:padding="12dp" + android:text="@string/btn_code_wrotedown" /> + + <Space + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:orientation="vertical"> + + <TextView + style="?android:textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:text="@string/backup_code_wrong" /> + + <Button + android:id="@+id/button_backup_back" + style="?android:buttonBarButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_margin="10dp" + android:drawableLeft="@drawable/ic_repeat_grey_24dp" + android:drawablePadding="8dp" + android:padding="12dp" + android:text="@string/btn_backup_back" /> + + </LinearLayout> + + <LinearLayout + style="?android:buttonBarStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:orientation="vertical"> + + <LinearLayout + style="?android:buttonBarStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal"> + + <Button + android:id="@+id/button_backup_share" + style="?android:buttonBarButtonStyle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:layout_weight="1" + android:drawableLeft="@drawable/ic_share_grey_24dp" + android:drawablePadding="8dp" + android:padding="12dp" + android:text="@string/btn_backup_share" /> + + <Button + android:id="@+id/button_backup_save" + style="?android:buttonBarButtonStyle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:layout_weight="1" + android:drawableLeft="@drawable/ic_save_grey_24dp" + android:drawablePadding="8dp" + android:padding="12dp" + android:text="@string/btn_backup_save" /> + + + </LinearLayout> + + <Button + android:id="@+id/button_faq" + style="?android:buttonBarButtonStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/how_to_import" /> + </LinearLayout> + + </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator> + +</LinearLayout> diff --git a/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml b/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml index 0ffa695cf..b17c9dba7 100644 --- a/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml +++ b/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -27,99 +28,22 @@ android:layout_gravity="center_horizontal" android:layout_marginTop="8dp"> - <!-- - The most reliable way to correctly size these I found was to put a transparent hint on them. - Theoretically, this should be what the android:ems attribute is for - didn't work for me. - --> - <EditText - android:id="@+id/backup_code_1" + <com.github.pinball83.maskededittext.MaskedEditText + android:id="@+id/backup_code" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="14dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:textSize="18dp" android:textStyle="bold" android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="14dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="14dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="14dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_3" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="14dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:text="-" - android:textSize="14dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> - - <EditText - android:id="@+id/backup_code_4" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:hint="ABCDEF" - android:inputType="textNoSuggestions|textCapCharacters" - android:maxLength="6" - android:singleLine="true" - android:textColorHint="@android:color/transparent" - android:textSize="14dp" - android:textStyle="bold" - android:typeface="monospace" - tools:ignore="HardcodedText,SpUsage" /> + app:deleteChar="\u00a0" + app:mask="****-****-****-****-****-****" + app:maskIconColor="@color/colorPrimary" + app:notMaskedSymbol="*" + app:replacementChar="\u00a0" + tools:ignore="SpUsage" /> </LinearLayout> </LinearLayout> |