Merge pull request #2304 from open-keychain/autocrypt-setup-message
Autocrypt setup message format support
This commit is contained in:
@@ -454,6 +454,14 @@
|
|||||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
|
||||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter android:label="@string/intent_autocrypt_setup">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:mimeType="application/autocrypt-setup" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.UploadKeyActivity"
|
android:name=".ui.UploadKeyActivity"
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
|
|||||||
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
|
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.Numeric9x4PassphraseUtil;
|
||||||
import org.sufficientlysecure.keychain.util.CountingOutputStream;
|
import org.sufficientlysecure.keychain.util.CountingOutputStream;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
@@ -127,8 +129,8 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CountingOutputStream outStream = new CountingOutputStream(new BufferedOutputStream(plainOut));
|
CountingOutputStream outStream = new CountingOutputStream(new BufferedOutputStream(plainOut));
|
||||||
boolean backupSuccess = exportKeysToStream(
|
boolean backupSuccess = exportKeysToStream(log, backupInput.getMasterKeyIds(),
|
||||||
log, backupInput.getMasterKeyIds(), backupInput.getExportSecret(), outStream);
|
backupInput.getExportSecret(), backupInput.getExportPublic(), outStream);
|
||||||
|
|
||||||
if (!backupSuccess) {
|
if (!backupSuccess) {
|
||||||
// if there was an error, it will be in the log so we just have to return
|
// if there was an error, it will be in the log so we just have to return
|
||||||
@@ -169,9 +171,15 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
|
|||||||
PgpSignEncryptOperation signEncryptOperation = new PgpSignEncryptOperation(mContext, mKeyRepository, mProgressable, mCancelled);
|
PgpSignEncryptOperation signEncryptOperation = new PgpSignEncryptOperation(mContext, mKeyRepository, mProgressable, mCancelled);
|
||||||
|
|
||||||
PgpSignEncryptData.Builder builder = PgpSignEncryptData.builder();
|
PgpSignEncryptData.Builder builder = PgpSignEncryptData.builder();
|
||||||
builder.setSymmetricPassphrase(cryptoInput.getPassphrase());
|
Passphrase passphrase = cryptoInput.getPassphrase();
|
||||||
|
builder.setSymmetricPassphrase(passphrase);
|
||||||
builder.setEnableAsciiArmorOutput(backupInput.getEnableAsciiArmorOutput());
|
builder.setEnableAsciiArmorOutput(backupInput.getEnableAsciiArmorOutput());
|
||||||
builder.setAddBackupHeader(true);
|
boolean isNumeric9x4Passphrase = passphrase != null && Numeric9x4PassphraseUtil.isNumeric9x4Passphrase(passphrase);
|
||||||
|
if (isNumeric9x4Passphrase) {
|
||||||
|
builder.setPassphraseFormat("numeric9x4");
|
||||||
|
char[] passphraseChars = passphrase.getCharArray();
|
||||||
|
builder.setPassphraseBegin("" + passphraseChars[0] + passphraseChars[1]);
|
||||||
|
}
|
||||||
PgpSignEncryptData pgpSignEncryptData = builder.build();
|
PgpSignEncryptData pgpSignEncryptData = builder.build();
|
||||||
|
|
||||||
InputStream inStream = mContext.getContentResolver().openInputStream(plainUri);
|
InputStream inStream = mContext.getContentResolver().openInputStream(plainUri);
|
||||||
@@ -206,7 +214,8 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
|
|||||||
pgpSignEncryptData, CryptoInputParcel.createCryptoInputParcel(), inputData, outStream);
|
pgpSignEncryptData, CryptoInputParcel.createCryptoInputParcel(), inputData, outStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean exportKeysToStream(OperationLog log, long[] masterKeyIds, boolean exportSecret, OutputStream outStream) {
|
boolean exportKeysToStream(OperationLog log, long[] masterKeyIds, boolean exportSecret, boolean exportPublic,
|
||||||
|
OutputStream outStream) {
|
||||||
// noinspection unused TODO use these in a log entry
|
// noinspection unused TODO use these in a log entry
|
||||||
int okSecret = 0, okPublic = 0;
|
int okSecret = 0, okPublic = 0;
|
||||||
|
|
||||||
@@ -232,9 +241,15 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
|
|||||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||||
log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(masterKeyId));
|
log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(masterKeyId));
|
||||||
|
|
||||||
if (writePublicKeyToStream(masterKeyId, log, outStream)) {
|
boolean publicKeyWriteOk = false;
|
||||||
okPublic += 1;
|
if (exportPublic) {
|
||||||
|
publicKeyWriteOk = writePublicKeyToStream(masterKeyId, log, outStream);
|
||||||
|
if (publicKeyWriteOk) {
|
||||||
|
okPublic += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publicKeyWriteOk || !exportPublic) {
|
||||||
boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0;
|
boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0;
|
||||||
if (exportSecret && hasSecret) {
|
if (exportSecret && hasSecret) {
|
||||||
log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(masterKeyId));
|
log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(masterKeyId));
|
||||||
|
|||||||
@@ -627,6 +627,8 @@ public abstract class OperationResult implements Parcelable {
|
|||||||
MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym),
|
MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym),
|
||||||
MSG_DC_CHARSET (LogLevel.DEBUG, R.string.msg_dc_charset),
|
MSG_DC_CHARSET (LogLevel.DEBUG, R.string.msg_dc_charset),
|
||||||
MSG_DC_BACKUP_VERSION (LogLevel.DEBUG, R.string.msg_dc_backup_version),
|
MSG_DC_BACKUP_VERSION (LogLevel.DEBUG, R.string.msg_dc_backup_version),
|
||||||
|
MSG_DC_PASSPHRASE_FORMAT (LogLevel.DEBUG, R.string.msg_dc_passphrase_format),
|
||||||
|
MSG_DC_PASSPHRASE_BEGIN (LogLevel.DEBUG, R.string.msg_dc_passphrase_begin),
|
||||||
MSG_DC_CLEAR_DATA (LogLevel.DEBUG, R.string.msg_dc_clear_data),
|
MSG_DC_CLEAR_DATA (LogLevel.DEBUG, R.string.msg_dc_clear_data),
|
||||||
MSG_DC_CLEAR_DECOMPRESS (LogLevel.DEBUG, R.string.msg_dc_clear_decompress),
|
MSG_DC_CLEAR_DECOMPRESS (LogLevel.DEBUG, R.string.msg_dc_clear_decompress),
|
||||||
MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file),
|
MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file),
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public abstract class PgpDecryptVerifyInputParcel implements Parcelable {
|
|||||||
|
|
||||||
abstract boolean isAllowSymmetricDecryption();
|
abstract boolean isAllowSymmetricDecryption();
|
||||||
abstract boolean isDecryptMetadataOnly();
|
abstract boolean isDecryptMetadataOnly();
|
||||||
|
abstract boolean isAutocryptSetup();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
abstract List<Long> getAllowedKeyIds();
|
abstract List<Long> getAllowedKeyIds();
|
||||||
@@ -55,7 +56,8 @@ public abstract class PgpDecryptVerifyInputParcel implements Parcelable {
|
|||||||
public static Builder builder() {
|
public static Builder builder() {
|
||||||
return new AutoValue_PgpDecryptVerifyInputParcel.Builder()
|
return new AutoValue_PgpDecryptVerifyInputParcel.Builder()
|
||||||
.setAllowSymmetricDecryption(false)
|
.setAllowSymmetricDecryption(false)
|
||||||
.setDecryptMetadataOnly(false);
|
.setDecryptMetadataOnly(false)
|
||||||
|
.setAutocryptSetup(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue.Builder
|
@AutoValue.Builder
|
||||||
@@ -68,6 +70,7 @@ public abstract class PgpDecryptVerifyInputParcel implements Parcelable {
|
|||||||
public abstract Builder setDecryptMetadataOnly(boolean decryptMetadataOnly);
|
public abstract Builder setDecryptMetadataOnly(boolean decryptMetadataOnly);
|
||||||
public abstract Builder setDetachedSignature(byte[] detachedSignature);
|
public abstract Builder setDetachedSignature(byte[] detachedSignature);
|
||||||
public abstract Builder setSenderAddress(String senderAddress);
|
public abstract Builder setSenderAddress(String senderAddress);
|
||||||
|
public abstract Builder setAutocryptSetup(boolean isAutocryptSetup);
|
||||||
|
|
||||||
public abstract Builder setAllowedKeyIds(List<Long> allowedKeyIds);
|
public abstract Builder setAllowedKeyIds(List<Long> allowedKeyIds);
|
||||||
abstract List<Long> getAllowedKeyIds();
|
abstract List<Long> getAllowedKeyIds();
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ import static java.lang.String.format;
|
|||||||
public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInputParcel> {
|
public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInputParcel> {
|
||||||
|
|
||||||
public static final int PROGRESS_STRIDE_MILLISECONDS = 200;
|
public static final int PROGRESS_STRIDE_MILLISECONDS = 200;
|
||||||
|
public static final String PASSPHRASE_FORMAT_NUMERIC9X4 = "numeric9x4";
|
||||||
|
|
||||||
public PgpDecryptVerifyOperation(Context context, KeyRepository keyRepository, Progressable progressable) {
|
public PgpDecryptVerifyOperation(Context context, KeyRepository keyRepository, Progressable progressable) {
|
||||||
super(context, keyRepository, progressable);
|
super(context, keyRepository, progressable);
|
||||||
@@ -230,6 +231,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
private static class ArmorHeaders {
|
private static class ArmorHeaders {
|
||||||
String charset = null;
|
String charset = null;
|
||||||
Integer backupVersion = null;
|
Integer backupVersion = null;
|
||||||
|
String passphraseFormat;
|
||||||
|
String passphraseBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArmorHeaders parseArmorHeaders(InputStream in, OperationLog log, int indent) {
|
private ArmorHeaders parseArmorHeaders(InputStream in, OperationLog log, int indent) {
|
||||||
@@ -261,6 +264,14 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "passphrase-format": {
|
||||||
|
armorHeaders.passphraseFormat = pieces[1].trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "passphrase-begin": {
|
||||||
|
armorHeaders.passphraseBegin = pieces[1].trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
@@ -272,6 +283,12 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
if (armorHeaders.backupVersion != null) {
|
if (armorHeaders.backupVersion != null) {
|
||||||
log.add(LogType.MSG_DC_BACKUP_VERSION, indent, Integer.toString(armorHeaders.backupVersion));
|
log.add(LogType.MSG_DC_BACKUP_VERSION, indent, Integer.toString(armorHeaders.backupVersion));
|
||||||
}
|
}
|
||||||
|
if (armorHeaders.passphraseFormat != null) {
|
||||||
|
log.add(LogType.MSG_DC_PASSPHRASE_FORMAT, indent, armorHeaders.passphraseFormat);
|
||||||
|
}
|
||||||
|
if (armorHeaders.passphraseBegin != null) {
|
||||||
|
log.add(LogType.MSG_DC_PASSPHRASE_BEGIN, indent, armorHeaders.passphraseBegin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,9 +311,16 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
// parse ASCII Armor headers
|
// parse ASCII Armor headers
|
||||||
ArmorHeaders armorHeaders = parseArmorHeaders(in, log, indent);
|
ArmorHeaders armorHeaders = parseArmorHeaders(in, log, indent);
|
||||||
String charset = armorHeaders.charset;
|
String charset = armorHeaders.charset;
|
||||||
boolean useBackupCode = false;
|
RequiredInputParcel customRequiredInputParcel = null;
|
||||||
if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 2) {
|
if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 2) {
|
||||||
useBackupCode = true;
|
customRequiredInputParcel = RequiredInputParcel.createRequiredBackupCode();
|
||||||
|
} else if (PASSPHRASE_FORMAT_NUMERIC9X4.equalsIgnoreCase(armorHeaders.passphraseFormat)) {
|
||||||
|
if (input.isAutocryptSetup()) {
|
||||||
|
customRequiredInputParcel =
|
||||||
|
RequiredInputParcel.createRequiredNumeric9x4Autocrypt(armorHeaders.passphraseBegin);
|
||||||
|
} else {
|
||||||
|
customRequiredInputParcel = RequiredInputParcel.createRequiredNumeric9x4(armorHeaders.passphraseBegin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder();
|
OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder();
|
||||||
@@ -311,7 +335,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
|
|
||||||
if (obj instanceof PGPEncryptedDataList) {
|
if (obj instanceof PGPEncryptedDataList) {
|
||||||
esResult = handleEncryptedPacket(
|
esResult = handleEncryptedPacket(
|
||||||
input, cryptoInput, (PGPEncryptedDataList) obj, log, indent, useBackupCode);
|
input, cryptoInput, (PGPEncryptedDataList) obj, log, indent, customRequiredInputParcel);
|
||||||
|
|
||||||
// if there is an error, nothing left to do here
|
// if there is an error, nothing left to do here
|
||||||
if (esResult.errorResult != null) {
|
if (esResult.errorResult != null) {
|
||||||
@@ -565,7 +589,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
|
private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
|
||||||
PGPEncryptedDataList enc, OperationLog log, int indent, boolean useBackupCode) throws PGPException {
|
PGPEncryptedDataList enc, OperationLog log, int indent, RequiredInputParcel customRequiredInputParcel)
|
||||||
|
throws PGPException {
|
||||||
|
|
||||||
EncryptStreamResult result = new EncryptStreamResult();
|
EncryptStreamResult result = new EncryptStreamResult();
|
||||||
|
|
||||||
@@ -723,9 +748,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
|
|
||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
|
log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
|
||||||
RequiredInputParcel requiredInputParcel = useBackupCode ?
|
RequiredInputParcel requiredInputParcel = customRequiredInputParcel != null ?
|
||||||
RequiredInputParcel.createRequiredBackupCode() :
|
customRequiredInputParcel : RequiredInputParcel.createRequiredSymmetricPassphrase();
|
||||||
RequiredInputParcel.createRequiredSymmetricPassphrase();
|
|
||||||
return result.with(new DecryptVerifyResult(log,
|
return result.with(new DecryptVerifyResult(log,
|
||||||
requiredInputParcel,
|
requiredInputParcel,
|
||||||
cryptoInput));
|
cryptoInput));
|
||||||
@@ -771,9 +795,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
|||||||
result.cleartextStream = encryptedDataSymmetric.getDataStream(decryptorFactory);
|
result.cleartextStream = encryptedDataSymmetric.getDataStream(decryptorFactory);
|
||||||
} catch (PGPDataValidationException e) {
|
} catch (PGPDataValidationException e) {
|
||||||
log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent + 1);
|
log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent + 1);
|
||||||
RequiredInputParcel requiredInputParcel = useBackupCode ?
|
RequiredInputParcel requiredInputParcel = customRequiredInputParcel != null ?
|
||||||
RequiredInputParcel.createRequiredBackupCode() :
|
customRequiredInputParcel : RequiredInputParcel.createRequiredSymmetricPassphrase();
|
||||||
RequiredInputParcel.createRequiredSymmetricPassphrase();
|
|
||||||
return result.with(new DecryptVerifyResult(log, requiredInputParcel, cryptoInput));
|
return result.with(new DecryptVerifyResult(log, requiredInputParcel, cryptoInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,13 @@ public abstract class PgpSignEncryptData implements Parcelable {
|
|||||||
public abstract boolean isEnableAsciiArmorOutput();
|
public abstract boolean isEnableAsciiArmorOutput();
|
||||||
public abstract boolean isCleartextSignature();
|
public abstract boolean isCleartextSignature();
|
||||||
public abstract boolean isDetachedSignature();
|
public abstract boolean isDetachedSignature();
|
||||||
public abstract boolean isAddBackupHeader();
|
|
||||||
public abstract boolean isHiddenRecipients();
|
public abstract boolean isHiddenRecipients();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public abstract String getPassphraseFormat();
|
||||||
|
@Nullable
|
||||||
|
public abstract String getPassphraseBegin();
|
||||||
|
|
||||||
public static Builder builder() {
|
public static Builder builder() {
|
||||||
return new AutoValue_PgpSignEncryptData.Builder()
|
return new AutoValue_PgpSignEncryptData.Builder()
|
||||||
.setSignatureMasterKeyId(Constants.key.none)
|
.setSignatureMasterKeyId(Constants.key.none)
|
||||||
@@ -68,7 +72,6 @@ public abstract class PgpSignEncryptData implements Parcelable {
|
|||||||
.setEnableAsciiArmorOutput(false)
|
.setEnableAsciiArmorOutput(false)
|
||||||
.setCleartextSignature(false)
|
.setCleartextSignature(false)
|
||||||
.setDetachedSignature(false)
|
.setDetachedSignature(false)
|
||||||
.setAddBackupHeader(false)
|
|
||||||
.setHiddenRecipients(false)
|
.setHiddenRecipients(false)
|
||||||
.setCompressionAlgorithm(OpenKeychainCompressionAlgorithmTags.USE_DEFAULT)
|
.setCompressionAlgorithm(OpenKeychainCompressionAlgorithmTags.USE_DEFAULT)
|
||||||
.setSignatureHashAlgorithm(OpenKeychainHashAlgorithmTags.USE_DEFAULT)
|
.setSignatureHashAlgorithm(OpenKeychainHashAlgorithmTags.USE_DEFAULT)
|
||||||
@@ -91,7 +94,6 @@ public abstract class PgpSignEncryptData implements Parcelable {
|
|||||||
public abstract Builder setSignatureHashAlgorithm(int signatureHashAlgorithm);
|
public abstract Builder setSignatureHashAlgorithm(int signatureHashAlgorithm);
|
||||||
public abstract Builder setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm);
|
public abstract Builder setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm);
|
||||||
|
|
||||||
public abstract Builder setAddBackupHeader(boolean isAddBackupHeader);
|
|
||||||
public abstract Builder setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput);
|
public abstract Builder setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput);
|
||||||
public abstract Builder setCleartextSignature(boolean isCleartextSignature);
|
public abstract Builder setCleartextSignature(boolean isCleartextSignature);
|
||||||
public abstract Builder setDetachedSignature(boolean isDetachedSignature);
|
public abstract Builder setDetachedSignature(boolean isDetachedSignature);
|
||||||
@@ -102,6 +104,9 @@ public abstract class PgpSignEncryptData implements Parcelable {
|
|||||||
setAllowedSigningKeyIds(Collections.unmodifiableList(new ArrayList<>(allowedSigningKeyIds)));
|
setAllowedSigningKeyIds(Collections.unmodifiableList(new ArrayList<>(allowedSigningKeyIds)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract Builder setPassphraseFormat(String passphraseFormat);
|
||||||
|
public abstract Builder setPassphraseBegin(String passphraseBegin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,9 +202,13 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
|
|||||||
if (data.getCharset() != null) {
|
if (data.getCharset() != null) {
|
||||||
armorOut.setHeader("Charset", data.getCharset());
|
armorOut.setHeader("Charset", data.getCharset());
|
||||||
}
|
}
|
||||||
// add proprietary header to indicate that this is a key backup
|
String passphraseFormat = data.getPassphraseFormat();
|
||||||
if (data.isAddBackupHeader()) {
|
if (passphraseFormat != null) {
|
||||||
armorOut.setHeader("BackupVersion", "2");
|
armorOut.setHeader("Passphrase-Format", passphraseFormat);
|
||||||
|
}
|
||||||
|
String passphraseBegin = data.getPassphraseBegin();
|
||||||
|
if (passphraseBegin != null) {
|
||||||
|
armorOut.setHeader("Passphrase-Begin", passphraseBegin);
|
||||||
}
|
}
|
||||||
out = armorOut;
|
out = armorOut;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ public class OpenPgpService extends Service {
|
|||||||
// the backup code is cached in CryptoInputParcelCacheService, now we can proceed
|
// the backup code is cached in CryptoInputParcelCacheService, now we can proceed
|
||||||
|
|
||||||
BackupKeyringParcel input = BackupKeyringParcel
|
BackupKeyringParcel input = BackupKeyringParcel
|
||||||
.createBackupKeyringParcel(masterKeyIds, backupSecret, true, enableAsciiArmorOutput, null);
|
.create(masterKeyIds, backupSecret, true, enableAsciiArmorOutput, null);
|
||||||
BackupOperation op = new BackupOperation(this, mKeyRepository, null);
|
BackupOperation op = new BackupOperation(this, mKeyRepository, null);
|
||||||
ExportResult pgpResult = op.execute(input, inputParcel, outputStream);
|
ExportResult pgpResult = op.execute(input, inputParcel, outputStream);
|
||||||
|
|
||||||
|
|||||||
@@ -31,14 +31,20 @@ public abstract class BackupKeyringParcel implements Parcelable {
|
|||||||
@SuppressWarnings("mutable")
|
@SuppressWarnings("mutable")
|
||||||
public abstract long[] getMasterKeyIds();
|
public abstract long[] getMasterKeyIds();
|
||||||
public abstract boolean getExportSecret();
|
public abstract boolean getExportSecret();
|
||||||
|
public abstract boolean getExportPublic();
|
||||||
public abstract boolean getIsEncrypted();
|
public abstract boolean getIsEncrypted();
|
||||||
public abstract boolean getEnableAsciiArmorOutput();
|
public abstract boolean getEnableAsciiArmorOutput();
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract Uri getOutputUri();
|
public abstract Uri getOutputUri();
|
||||||
|
|
||||||
public static BackupKeyringParcel createBackupKeyringParcel(long[] masterKeyIds, boolean exportSecret,
|
public static BackupKeyringParcel create(long[] masterKeyIds, boolean exportSecret,
|
||||||
boolean isEncrypted, boolean enableAsciiArmorOutput, Uri outputUri) {
|
boolean isEncrypted, boolean enableAsciiArmorOutput, Uri outputUri) {
|
||||||
return new AutoValue_BackupKeyringParcel(
|
return new AutoValue_BackupKeyringParcel(
|
||||||
masterKeyIds, exportSecret, isEncrypted, enableAsciiArmorOutput, outputUri);
|
masterKeyIds, exportSecret, true, isEncrypted, enableAsciiArmorOutput, outputUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BackupKeyringParcel createExportAutocryptSetupMessage(long[] masterKeyIds) {
|
||||||
|
return new AutoValue_BackupKeyringParcel(
|
||||||
|
masterKeyIds, true, false, true, true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,9 +31,17 @@ import org.sufficientlysecure.keychain.util.Passphrase;
|
|||||||
|
|
||||||
public class RequiredInputParcel implements Parcelable {
|
public class RequiredInputParcel implements Parcelable {
|
||||||
|
|
||||||
|
public boolean hasPassphraseBegin() {
|
||||||
|
return mInputData != null && mInputData.length == 1 && mInputData[0].length == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassphraseBegin() {
|
||||||
|
return new String(mInputData[0]);
|
||||||
|
}
|
||||||
|
|
||||||
public enum RequiredInputType {
|
public enum RequiredInputType {
|
||||||
PASSPHRASE, PASSPHRASE_SYMMETRIC, PASSPHRASE_AUTH,
|
PASSPHRASE, PASSPHRASE_SYMMETRIC, PASSPHRASE_AUTH,
|
||||||
BACKUP_CODE,
|
BACKUP_CODE, NUMERIC_9X4, NUMERIC_9X4_AUTOCRYPT,
|
||||||
SECURITY_TOKEN_SIGN, SECURITY_TOKEN_AUTH, SECURITY_TOKEN_DECRYPT,
|
SECURITY_TOKEN_SIGN, SECURITY_TOKEN_AUTH, SECURITY_TOKEN_DECRYPT,
|
||||||
SECURITY_TOKEN_MOVE_KEY_TO_CARD, SECURITY_TOKEN_RESET_CARD,
|
SECURITY_TOKEN_MOVE_KEY_TO_CARD, SECURITY_TOKEN_RESET_CARD,
|
||||||
ENABLE_ORBOT, UPLOAD_FAIL_RETRY
|
ENABLE_ORBOT, UPLOAD_FAIL_RETRY
|
||||||
@@ -179,6 +187,18 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
null, null, null, (long[]) null, null);
|
null, null, null, (long[]) null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RequiredInputParcel createRequiredNumeric9x4(String beginChars) {
|
||||||
|
byte[][] inputData = beginChars != null ? new byte[][] { beginChars.getBytes() } : null;
|
||||||
|
return new RequiredInputParcel(RequiredInputType.NUMERIC_9X4,
|
||||||
|
inputData, null, null, (long[]) null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RequiredInputParcel createRequiredNumeric9x4Autocrypt(String beginChars) {
|
||||||
|
byte[][] inputData = beginChars != null ? new byte[][] { beginChars.getBytes() } : null;
|
||||||
|
return new RequiredInputParcel(RequiredInputType.NUMERIC_9X4_AUTOCRYPT,
|
||||||
|
inputData, null, null, (long[]) null, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static RequiredInputParcel createRequiredPassphrase(
|
public static RequiredInputParcel createRequiredPassphrase(
|
||||||
RequiredInputParcel req) {
|
RequiredInputParcel req) {
|
||||||
return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
|
return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import android.animation.ArgbEvaluator;
|
import android.animation.ArgbEvaluator;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
@@ -52,7 +50,6 @@ import android.view.View;
|
|||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.AccelerateInterpolator;
|
import android.view.animation.AccelerateInterpolator;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
@@ -66,6 +63,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
|
|||||||
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
|
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
|
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
|
||||||
|
import org.sufficientlysecure.keychain.util.Numeric9x4PassphraseUtil;
|
||||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
@@ -83,20 +81,13 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
public static final int REQUEST_SAVE = 1;
|
public static final int REQUEST_SAVE = 1;
|
||||||
public static final String ARG_BACK_STACK = "back_stack";
|
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
|
// argument variables
|
||||||
private boolean mExportSecret;
|
private boolean mExportSecret;
|
||||||
private long[] mMasterKeyIds;
|
private long[] mMasterKeyIds;
|
||||||
String mBackupCode;
|
Passphrase mBackupCode;
|
||||||
private boolean mExecuteBackupOperation;
|
private boolean mExecuteBackupOperation;
|
||||||
|
|
||||||
private EditText[] mCodeEditText;
|
private TextView[] mCodeEditText;
|
||||||
|
|
||||||
private ToolableViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator;
|
private ToolableViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator;
|
||||||
private Integer mBackStackLevel;
|
private Integer mBackStackLevel;
|
||||||
@@ -110,7 +101,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
BackupCodeFragment frag = new BackupCodeFragment();
|
BackupCodeFragment frag = new BackupCodeFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_BACKUP_CODE, generateRandomBackupCode());
|
args.putParcelable(ARG_BACKUP_CODE, Numeric9x4PassphraseUtil.generateNumeric9x4Passphrase());
|
||||||
args.putLongArray(ARG_MASTER_KEY_IDS, masterKeyIds);
|
args.putLongArray(ARG_MASTER_KEY_IDS, masterKeyIds);
|
||||||
args.putBoolean(ARG_EXPORT_SECRET, exportSecret);
|
args.putBoolean(ARG_EXPORT_SECRET, exportSecret);
|
||||||
args.putBoolean(ARG_EXECUTE_BACKUP_OPERATION, executeBackupOperation);
|
args.putBoolean(ARG_EXECUTE_BACKUP_OPERATION, executeBackupOperation);
|
||||||
@@ -149,13 +140,16 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
item.setChecked(newCheckedState);
|
item.setChecked(newCheckedState);
|
||||||
mDebugModeAcceptAnyCode = newCheckedState;
|
mDebugModeAcceptAnyCode = newCheckedState;
|
||||||
if (newCheckedState && TextUtils.isEmpty(mCodeEditText[0].getText())) {
|
if (newCheckedState && TextUtils.isEmpty(mCodeEditText[0].getText())) {
|
||||||
mCodeEditText[0].setText("ABCD");
|
mCodeEditText[0].setText("1234");
|
||||||
mCodeEditText[1].setText("EFGH");
|
mCodeEditText[1].setText("5678");
|
||||||
mCodeEditText[2].setText("IJKL");
|
mCodeEditText[2].setText("9012");
|
||||||
mCodeEditText[3].setText("MNOP");
|
mCodeEditText[3].setText("3456");
|
||||||
mCodeEditText[4].setText("QRST");
|
mCodeEditText[4].setText("7890");
|
||||||
mCodeEditText[5].setText("UVWX");
|
mCodeEditText[5].setText("1234");
|
||||||
Notify.create(getActivity(), "Actual backup code is all 'A's", Style.WARN).show();
|
mCodeEditText[6].setText("5678");
|
||||||
|
mCodeEditText[7].setText("9012");
|
||||||
|
mCodeEditText[8].setText("3456");
|
||||||
|
Notify.create(getActivity(), "Actual backup code is all '1's", Style.WARN).show();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -178,7 +172,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
mTitleAnimator.setDisplayedChild(1, animate);
|
mTitleAnimator.setDisplayedChild(1, animate);
|
||||||
mStatusAnimator.setDisplayedChild(1, animate);
|
mStatusAnimator.setDisplayedChild(1, animate);
|
||||||
mCodeFieldsAnimator.setDisplayedChild(1, animate);
|
mCodeFieldsAnimator.setDisplayedChild(1, animate);
|
||||||
for (EditText editText : mCodeEditText) {
|
for (TextView editText : mCodeEditText) {
|
||||||
editText.setText("");
|
editText.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +207,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
|
|
||||||
hideKeyboard();
|
hideKeyboard();
|
||||||
|
|
||||||
for (EditText editText : mCodeEditText) {
|
for (TextView editText : mCodeEditText) {
|
||||||
editText.setEnabled(false);
|
editText.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,30 +249,18 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
View view = inflater.inflate(R.layout.backup_code_fragment, container, false);
|
View view = inflater.inflate(R.layout.backup_code_fragment, container, false);
|
||||||
|
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
mBackupCode = args.getString(ARG_BACKUP_CODE);
|
mBackupCode = args.getParcelable(ARG_BACKUP_CODE);
|
||||||
mMasterKeyIds = args.getLongArray(ARG_MASTER_KEY_IDS);
|
mMasterKeyIds = args.getLongArray(ARG_MASTER_KEY_IDS);
|
||||||
mExportSecret = args.getBoolean(ARG_EXPORT_SECRET);
|
mExportSecret = args.getBoolean(ARG_EXPORT_SECRET);
|
||||||
mExecuteBackupOperation = args.getBoolean(ARG_EXECUTE_BACKUP_OPERATION, true);
|
mExecuteBackupOperation = args.getBoolean(ARG_EXECUTE_BACKUP_OPERATION, true);
|
||||||
|
|
||||||
mCodeEditText = new EditText[6];
|
mCodeEditText = getTransferCodeTextViews(view, R.id.transfer_code_input);
|
||||||
mCodeEditText[0] = view.findViewById(R.id.backup_code_1);
|
|
||||||
mCodeEditText[1] = view.findViewById(R.id.backup_code_2);
|
|
||||||
mCodeEditText[2] = view.findViewById(R.id.backup_code_3);
|
|
||||||
mCodeEditText[3] = view.findViewById(R.id.backup_code_4);
|
|
||||||
mCodeEditText[4] = view.findViewById(R.id.backup_code_5);
|
|
||||||
mCodeEditText[5] = view.findViewById(R.id.backup_code_6);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
TextView[] codeDisplayText = new TextView[6];
|
TextView[] codeDisplayText = getTransferCodeTextViews(view, R.id.transfer_code_display);
|
||||||
codeDisplayText[0] = view.findViewById(R.id.backup_code_display_1);
|
|
||||||
codeDisplayText[1] = view.findViewById(R.id.backup_code_display_2);
|
|
||||||
codeDisplayText[2] = view.findViewById(R.id.backup_code_display_3);
|
|
||||||
codeDisplayText[3] = view.findViewById(R.id.backup_code_display_4);
|
|
||||||
codeDisplayText[4] = view.findViewById(R.id.backup_code_display_5);
|
|
||||||
codeDisplayText[5] = view.findViewById(R.id.backup_code_display_6);
|
|
||||||
|
|
||||||
// set backup code in code TextViews
|
// set backup code in code TextViews
|
||||||
char[] backupCode = mBackupCode.toCharArray();
|
char[] backupCode = mBackupCode.getCharArray();
|
||||||
for (int i = 0; i < codeDisplayText.length; i++) {
|
for (int i = 0; i < codeDisplayText.length; i++) {
|
||||||
codeDisplayText[i].setText(backupCode, i * 5, 4);
|
codeDisplayText[i].setText(backupCode, i * 5, 4);
|
||||||
}
|
}
|
||||||
@@ -340,6 +322,22 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private TextView[] getTransferCodeTextViews(View view, int transferCodeViewGroupId) {
|
||||||
|
ViewGroup transferCodeGroup = view.findViewById(transferCodeViewGroupId);
|
||||||
|
TextView[] codeDisplayText = new TextView[9];
|
||||||
|
codeDisplayText[0] = transferCodeGroup.findViewById(R.id.transfer_code_block_1);
|
||||||
|
codeDisplayText[1] = transferCodeGroup.findViewById(R.id.transfer_code_block_2);
|
||||||
|
codeDisplayText[2] = transferCodeGroup.findViewById(R.id.transfer_code_block_3);
|
||||||
|
codeDisplayText[3] = transferCodeGroup.findViewById(R.id.transfer_code_block_4);
|
||||||
|
codeDisplayText[4] = transferCodeGroup.findViewById(R.id.transfer_code_block_5);
|
||||||
|
codeDisplayText[5] = transferCodeGroup.findViewById(R.id.transfer_code_block_6);
|
||||||
|
codeDisplayText[6] = transferCodeGroup.findViewById(R.id.transfer_code_block_7);
|
||||||
|
codeDisplayText[7] = transferCodeGroup.findViewById(R.id.transfer_code_block_8);
|
||||||
|
codeDisplayText[8] = transferCodeGroup.findViewById(R.id.transfer_code_block_9);
|
||||||
|
return codeDisplayText;
|
||||||
|
}
|
||||||
|
|
||||||
private void showFaq() {
|
private void showFaq() {
|
||||||
HelpActivity.startHelpActivity(getActivity(), HelpActivity.TAB_FAQ);
|
HelpActivity.startHelpActivity(getActivity(), HelpActivity.TAB_FAQ);
|
||||||
}
|
}
|
||||||
@@ -369,8 +367,8 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
outState.putInt(ARG_BACK_STACK, mBackStackLevel == null ? -1 : mBackStackLevel);
|
outState.putInt(ARG_BACK_STACK, mBackStackLevel == null ? -1 : mBackStackLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupEditTextSuccessListener(final EditText[] backupCodes) {
|
private void setupEditTextSuccessListener(final TextView[] backupCodes) {
|
||||||
for (EditText backupCode : backupCodes) {
|
for (TextView backupCode : backupCodes) {
|
||||||
|
|
||||||
backupCode.addTextChangedListener(new TextWatcher() {
|
backupCode.addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
@@ -410,7 +408,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder backupCodeInput = new StringBuilder(26);
|
StringBuilder backupCodeInput = new StringBuilder(26);
|
||||||
for (EditText editText : mCodeEditText) {
|
for (TextView editText : mCodeEditText) {
|
||||||
if (editText.getText().length() < 4) {
|
if (editText.getText().length() < 4) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -449,7 +447,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setupEditTextFocusNext(final EditText[] backupCodes) {
|
private static void setupEditTextFocusNext(final TextView[] backupCodes) {
|
||||||
for (int i = 0; i < backupCodes.length - 1; i++) {
|
for (int i = 0; i < backupCodes.length - 1; i++) {
|
||||||
|
|
||||||
final int next = i + 1;
|
final int next = i + 1;
|
||||||
@@ -516,9 +514,9 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
+ (mExportSecret ? Constants.FILE_EXTENSION_ENCRYPTED_BACKUP_SECRET
|
+ (mExportSecret ? Constants.FILE_EXTENSION_ENCRYPTED_BACKUP_SECRET
|
||||||
: Constants.FILE_EXTENSION_ENCRYPTED_BACKUP_PUBLIC);
|
: Constants.FILE_EXTENSION_ENCRYPTED_BACKUP_PUBLIC);
|
||||||
|
|
||||||
Passphrase passphrase = new Passphrase(mBackupCode);
|
Passphrase passphrase = new Passphrase(mBackupCode.getCharArray());
|
||||||
if (Constants.DEBUG && mDebugModeAcceptAnyCode) {
|
if (Constants.DEBUG && mDebugModeAcceptAnyCode) {
|
||||||
passphrase = new Passphrase("AAAA-AAAA-AAAA-AAAA-AAAA-AAAA");
|
passphrase = new Passphrase("1111-1111-1111-1111-1111-1111-1111-1111-1111");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't want to execute the actual operation outside of this activity, drop out here
|
// if we don't want to execute the actual operation outside of this activity, drop out here
|
||||||
@@ -612,7 +610,7 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
@Override
|
@Override
|
||||||
public BackupKeyringParcel createOperationInput() {
|
public BackupKeyringParcel createOperationInput() {
|
||||||
return BackupKeyringParcel
|
return BackupKeyringParcel
|
||||||
.createBackupKeyringParcel(mMasterKeyIds, mExportSecret, true, true, mCachedBackupUri);
|
.create(mMasterKeyIds, mExportSecret, true, true, mCachedBackupUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -631,27 +629,4 @@ public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringPar
|
|||||||
mCachedBackupUri = null;
|
mCachedBackupUri = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate backup code using format defined in
|
|
||||||
* https://github.com/open-keychain/open-keychain/wiki/Backups
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
private static String generateRandomBackupCode() {
|
|
||||||
|
|
||||||
Random r = new SecureRandom();
|
|
||||||
|
|
||||||
// simple generation of a 24 character backup code
|
|
||||||
StringBuilder code = new StringBuilder(28);
|
|
||||||
for (int i = 0; i < 24; i++) {
|
|
||||||
if (i == 4 || i == 8 || i == 12 || i == 16 || i == 20) {
|
|
||||||
code.append('-');
|
|
||||||
}
|
|
||||||
|
|
||||||
code.append(mBackupCodeAlphabet[r.nextInt(mBackupCodeAlphabet.length)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
|||||||
|
|
||||||
|
|
||||||
public class DecryptActivity extends BaseActivity {
|
public class DecryptActivity extends BaseActivity {
|
||||||
|
public static final String APPLICATION_AUTOCRYPT_SETUP = "application/autocrypt-setup";
|
||||||
|
|
||||||
/* Intents */
|
/* Intents */
|
||||||
public static final String ACTION_DECRYPT_FROM_CLIPBOARD = "DECRYPT_DATA_CLIPBOARD";
|
public static final String ACTION_DECRYPT_FROM_CLIPBOARD = "DECRYPT_DATA_CLIPBOARD";
|
||||||
@@ -84,6 +85,7 @@ public class DecryptActivity extends BaseActivity {
|
|||||||
|
|
||||||
// depending on the data source, we may or may not be able to delete the original file
|
// depending on the data source, we may or may not be able to delete the original file
|
||||||
boolean canDelete = false;
|
boolean canDelete = false;
|
||||||
|
boolean isAutocryptSetup = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -160,6 +162,9 @@ public class DecryptActivity extends BaseActivity {
|
|||||||
case Constants.DECRYPT_DATA:
|
case Constants.DECRYPT_DATA:
|
||||||
default:
|
default:
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
|
|
||||||
|
isAutocryptSetup = APPLICATION_AUTOCRYPT_SETUP.equalsIgnoreCase(intent.getType());
|
||||||
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
|
|
||||||
if ("com.android.email.attachmentprovider".equals(uri.getHost())) {
|
if ("com.android.email.attachmentprovider".equals(uri.getHost())) {
|
||||||
@@ -187,7 +192,7 @@ public class DecryptActivity extends BaseActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
displayListFragment(uris, canDelete);
|
displayListFragment(uris, canDelete, isAutocryptSetup);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,9 +216,9 @@ public class DecryptActivity extends BaseActivity {
|
|||||||
return tempFile;
|
return tempFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void displayListFragment(ArrayList<Uri> inputUris, boolean canDelete) {
|
public void displayListFragment(ArrayList<Uri> inputUris, boolean canDelete, boolean isAutocryptSetup) {
|
||||||
|
|
||||||
DecryptListFragment frag = DecryptListFragment.newInstance(inputUris, canDelete);
|
DecryptListFragment frag = DecryptListFragment.newInstance(inputUris, canDelete, isAutocryptSetup);
|
||||||
|
|
||||||
FragmentManager fragMan = getSupportFragmentManager();
|
FragmentManager fragMan = getSupportFragmentManager();
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ public class DecryptListFragment
|
|||||||
public static final String ARG_CANCELLED_URIS = "cancelled_uris";
|
public static final String ARG_CANCELLED_URIS = "cancelled_uris";
|
||||||
public static final String ARG_RESULTS = "results";
|
public static final String ARG_RESULTS = "results";
|
||||||
public static final String ARG_CAN_DELETE = "can_delete";
|
public static final String ARG_CAN_DELETE = "can_delete";
|
||||||
|
public static final String ARG_IS_AUTOCRYPT_SETUP = "is_autocrypt_setup";
|
||||||
|
|
||||||
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
|
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
|
||||||
private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 12;
|
private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 12;
|
||||||
@@ -136,6 +137,7 @@ public class DecryptListFragment
|
|||||||
|
|
||||||
private Uri mCurrentInputUri;
|
private Uri mCurrentInputUri;
|
||||||
private boolean mCanDelete;
|
private boolean mCanDelete;
|
||||||
|
private boolean mIsAutocryptSetup;
|
||||||
|
|
||||||
private DecryptFilesAdapter mAdapter;
|
private DecryptFilesAdapter mAdapter;
|
||||||
private Uri mCurrentSaveFileUri;
|
private Uri mCurrentSaveFileUri;
|
||||||
@@ -143,12 +145,13 @@ public class DecryptListFragment
|
|||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static DecryptListFragment newInstance(@NonNull ArrayList<Uri> uris, boolean canDelete) {
|
public static DecryptListFragment newInstance(@NonNull ArrayList<Uri> uris, boolean canDelete, boolean isAutocryptSetup) {
|
||||||
DecryptListFragment frag = new DecryptListFragment();
|
DecryptListFragment frag = new DecryptListFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putParcelableArrayList(ARG_INPUT_URIS, uris);
|
args.putParcelableArrayList(ARG_INPUT_URIS, uris);
|
||||||
args.putBoolean(ARG_CAN_DELETE, canDelete);
|
args.putBoolean(ARG_CAN_DELETE, canDelete);
|
||||||
|
args.putBoolean(ARG_IS_AUTOCRYPT_SETUP, isAutocryptSetup);
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
return frag;
|
return frag;
|
||||||
@@ -205,6 +208,7 @@ public class DecryptListFragment
|
|||||||
outState.putParcelable(ARG_OUTPUT_URIS, new ParcelableHashMap<>(mInputDataResults));
|
outState.putParcelable(ARG_OUTPUT_URIS, new ParcelableHashMap<>(mInputDataResults));
|
||||||
outState.putParcelableArrayList(ARG_CANCELLED_URIS, mCancelledInputUris);
|
outState.putParcelableArrayList(ARG_CANCELLED_URIS, mCancelledInputUris);
|
||||||
outState.putBoolean(ARG_CAN_DELETE, mCanDelete);
|
outState.putBoolean(ARG_CAN_DELETE, mCanDelete);
|
||||||
|
outState.putBoolean(ARG_IS_AUTOCRYPT_SETUP, mIsAutocryptSetup);
|
||||||
|
|
||||||
// this does not save mCurrentInputUri - if anything is being
|
// this does not save mCurrentInputUri - if anything is being
|
||||||
// processed at fragment recreation time, the operation in
|
// processed at fragment recreation time, the operation in
|
||||||
@@ -222,6 +226,7 @@ public class DecryptListFragment
|
|||||||
ParcelableHashMap<Uri, InputDataResult> results = args.getParcelable(ARG_RESULTS);
|
ParcelableHashMap<Uri, InputDataResult> results = args.getParcelable(ARG_RESULTS);
|
||||||
|
|
||||||
mCanDelete = args.getBoolean(ARG_CAN_DELETE, false);
|
mCanDelete = args.getBoolean(ARG_CAN_DELETE, false);
|
||||||
|
mIsAutocryptSetup = args.getBoolean(ARG_IS_AUTOCRYPT_SETUP, false);
|
||||||
|
|
||||||
displayInputUris(inputUris, cancelledUris,
|
displayInputUris(inputUris, cancelledUris,
|
||||||
results != null ? results.getMap() : null
|
results != null ? results.getMap() : null
|
||||||
@@ -638,11 +643,14 @@ public class DecryptListFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
PgpDecryptVerifyInputParcel.Builder decryptInput = PgpDecryptVerifyInputParcel.builder()
|
PgpDecryptVerifyInputParcel.Builder decryptInput = PgpDecryptVerifyInputParcel.builder()
|
||||||
.setAllowSymmetricDecryption(true);
|
.setAllowSymmetricDecryption(true)
|
||||||
|
.setAutocryptSetup(mIsAutocryptSetup);
|
||||||
return InputDataParcel.createInputDataParcel(mCurrentInputUri, decryptInput.build());
|
return InputDataParcel.createInputDataParcel(mCurrentInputUri, decryptInput.build());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request READ_EXTERNAL_STORAGE permission on Android >= 6.0 to read content from "file" Uris.
|
* Request READ_EXTERNAL_STORAGE permission on Android >= 6.0 to read content from "file" Uris.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.support.v4.app.DialogFragment;
|
|||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
|
import android.text.InputFilter;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.text.method.PasswordTransformationMethod;
|
import android.text.method.PasswordTransformationMethod;
|
||||||
@@ -68,6 +69,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.Require
|
|||||||
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
||||||
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
|
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.CacheTTLSpinner;
|
import org.sufficientlysecure.keychain.ui.widget.CacheTTLSpinner;
|
||||||
|
import org.sufficientlysecure.keychain.ui.widget.PrefixedEditText;
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -193,7 +195,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
mBackupCodeEditText[4] = view.findViewById(R.id.backup_code_5);
|
mBackupCodeEditText[4] = view.findViewById(R.id.backup_code_5);
|
||||||
mBackupCodeEditText[5] = view.findViewById(R.id.backup_code_6);
|
mBackupCodeEditText[5] = view.findViewById(R.id.backup_code_6);
|
||||||
|
|
||||||
setupEditTextFocusNext(mBackupCodeEditText);
|
setupEditTextFocusNext(mBackupCodeEditText, false);
|
||||||
|
|
||||||
AlertDialog dialog = alert.create();
|
AlertDialog dialog = alert.create();
|
||||||
dialog.setButton(DialogInterface.BUTTON_POSITIVE,
|
dialog.setButton(DialogInterface.BUTTON_POSITIVE,
|
||||||
@@ -201,6 +203,49 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mRequiredInput.mType == RequiredInputType.NUMERIC_9X4 ||
|
||||||
|
mRequiredInput.mType == RequiredInputType.NUMERIC_9X4_AUTOCRYPT) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(theme);
|
||||||
|
View view = inflater.inflate(R.layout.passphrase_dialog_numeric_9x4, null);
|
||||||
|
alert.setView(view);
|
||||||
|
|
||||||
|
mBackupCodeEditText = new EditText[9];
|
||||||
|
mBackupCodeEditText[0] = view.findViewById(R.id.transfer_code_block_1);
|
||||||
|
mBackupCodeEditText[1] = view.findViewById(R.id.transfer_code_block_2);
|
||||||
|
mBackupCodeEditText[2] = view.findViewById(R.id.transfer_code_block_3);
|
||||||
|
mBackupCodeEditText[3] = view.findViewById(R.id.transfer_code_block_4);
|
||||||
|
mBackupCodeEditText[4] = view.findViewById(R.id.transfer_code_block_5);
|
||||||
|
mBackupCodeEditText[5] = view.findViewById(R.id.transfer_code_block_6);
|
||||||
|
mBackupCodeEditText[6] = view.findViewById(R.id.transfer_code_block_7);
|
||||||
|
mBackupCodeEditText[7] = view.findViewById(R.id.transfer_code_block_8);
|
||||||
|
mBackupCodeEditText[8] = view.findViewById(R.id.transfer_code_block_9);
|
||||||
|
|
||||||
|
if (mRequiredInput.hasPassphraseBegin()) {
|
||||||
|
String beginChars = mRequiredInput.getPassphraseBegin();
|
||||||
|
int inputLength = 4 - beginChars.length();
|
||||||
|
setupEditTextFocusNext(mBackupCodeEditText, true);
|
||||||
|
|
||||||
|
PrefixedEditText prefixEditText = (PrefixedEditText) mBackupCodeEditText[0];
|
||||||
|
if (beginChars.matches("\\d\\d")) {
|
||||||
|
prefixEditText.setPrefix(beginChars);
|
||||||
|
prefixEditText.setHint("1234".substring(inputLength));
|
||||||
|
prefixEditText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(inputLength) });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setupEditTextFocusNext(mBackupCodeEditText, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRequiredInput.mType == RequiredInputType.NUMERIC_9X4_AUTOCRYPT) {
|
||||||
|
TextView promptText = view.findViewById(R.id.passphrase_text);
|
||||||
|
promptText.setText(R.string.passphrase_transfer_autocrypt);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog dialog = alert.create();
|
||||||
|
dialog.setButton(DialogInterface.BUTTON_POSITIVE,
|
||||||
|
activity.getString(R.string.btn_proceed), (DialogInterface.OnClickListener) null);
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(theme);
|
LayoutInflater inflater = LayoutInflater.from(theme);
|
||||||
mLayout = (ViewAnimator) inflater.inflate(R.layout.passphrase_dialog, null);
|
mLayout = (ViewAnimator) inflater.inflate(R.layout.passphrase_dialog, null);
|
||||||
alert.setView(mLayout);
|
alert.setView(mLayout);
|
||||||
@@ -377,10 +422,9 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
textView.requestFocus();
|
textView.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setupEditTextFocusNext(final EditText[] backupCodes) {
|
private static void setupEditTextFocusNext(EditText[] backupCodes, boolean hasPrefix) {
|
||||||
for (int i = 0; i < backupCodes.length - 1; i++) {
|
for (int i = 0; i < backupCodes.length - 1; i++) {
|
||||||
|
int idx = i;
|
||||||
final int next = i + 1;
|
|
||||||
|
|
||||||
backupCodes[i].addTextChangedListener(new TextWatcher() {
|
backupCodes[i].addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
@@ -390,10 +434,11 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
boolean inserting = before < count;
|
boolean inserting = before < count;
|
||||||
boolean cursorAtEnd = (start + count) == 4;
|
int maxLen = hasPrefix && idx == 0 ? 2 : 4;
|
||||||
|
boolean cursorAtEnd = (start + count) == maxLen;
|
||||||
|
|
||||||
if (inserting && cursorAtEnd) {
|
if (inserting && cursorAtEnd) {
|
||||||
backupCodes[next].requestFocus();
|
backupCodes[idx + 1].requestFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +446,6 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,6 +476,27 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mRequiredInput.mType == RequiredInputType.NUMERIC_9X4 ||
|
||||||
|
mRequiredInput.mType == RequiredInputType.NUMERIC_9X4_AUTOCRYPT) {
|
||||||
|
StringBuilder backupCodeInput = new StringBuilder(36);
|
||||||
|
if (mRequiredInput.hasPassphraseBegin()) {
|
||||||
|
backupCodeInput.append(mRequiredInput.getPassphraseBegin());
|
||||||
|
}
|
||||||
|
for (EditText editText : mBackupCodeEditText) {
|
||||||
|
if (editText.getText().length() != 2 && editText.getText().length() != 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backupCodeInput.append(editText.getText());
|
||||||
|
backupCodeInput.append('-');
|
||||||
|
}
|
||||||
|
backupCodeInput.deleteCharAt(backupCodeInput.length() - 1);
|
||||||
|
|
||||||
|
Passphrase passphrase = new Passphrase(backupCodeInput.toString());
|
||||||
|
finishCaching(passphrase, null);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final Passphrase passphrase = new Passphrase(mPassphraseEditText);
|
final Passphrase passphrase = new Passphrase(mPassphraseEditText);
|
||||||
final int timeToLiveSeconds = mTimeToLiveSpinner.getSelectedTimeToLive();
|
final int timeToLiveSeconds = mTimeToLiveSpinner.getSelectedTimeToLive();
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,9 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
|
|||||||
|
|
||||||
case PASSPHRASE:
|
case PASSPHRASE:
|
||||||
case PASSPHRASE_SYMMETRIC:
|
case PASSPHRASE_SYMMETRIC:
|
||||||
case BACKUP_CODE: {
|
case BACKUP_CODE:
|
||||||
|
case NUMERIC_9X4:
|
||||||
|
case NUMERIC_9X4_AUTOCRYPT: {
|
||||||
Intent intent = new Intent(activity, PassphraseDialogActivity.class);
|
Intent intent = new Intent(activity, PassphraseDialogActivity.class);
|
||||||
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
||||||
intent.putExtra(PassphraseDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
|
intent.putExtra(PassphraseDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
|
||||||
|
|||||||
@@ -21,21 +21,25 @@ import android.content.Context;
|
|||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.*;
|
import android.graphics.*;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.widget.AppCompatEditText;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.TextPaint;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
|
||||||
public class PrefixedEditText extends EditText {
|
public class PrefixedEditText extends AppCompatEditText {
|
||||||
|
|
||||||
private String mPrefix;
|
private CharSequence mPrefix;
|
||||||
private Rect mPrefixRect = new Rect();
|
private int mPrefixColor;
|
||||||
|
private int desiredWidth;
|
||||||
|
|
||||||
public PrefixedEditText(Context context, AttributeSet attrs) {
|
public PrefixedEditText(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
TypedArray style = context.getTheme().obtainStyledAttributes(
|
TypedArray style = context.getTheme().obtainStyledAttributes(
|
||||||
attrs, R.styleable.PrefixedEditText, 0, 0);
|
attrs, R.styleable.PrefixedEditText, 0, 0);
|
||||||
mPrefix = style.getString(R.styleable.PrefixedEditText_prefix);
|
mPrefix = style.getString(R.styleable.PrefixedEditText_prefix);
|
||||||
|
mPrefixColor = style.getColor(R.styleable.PrefixedEditText_prefixColor, getCurrentTextColor());
|
||||||
if (mPrefix == null) {
|
if (mPrefix == null) {
|
||||||
mPrefix = "";
|
mPrefix = "";
|
||||||
}
|
}
|
||||||
@@ -43,20 +47,29 @@ public class PrefixedEditText extends EditText {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
getPaint().getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixRect);
|
|
||||||
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
desiredWidth = (int) Math.ceil(Layout.getDesiredWidth(mPrefix, getPaint()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(@NonNull Canvas canvas) {
|
protected void onDraw(@NonNull Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
canvas.drawText(mPrefix, super.getCompoundPaddingLeft(), getBaseline(), getPaint());
|
TextPaint paint = getPaint();
|
||||||
|
// reset to the actual text color - it might be the hint color currently
|
||||||
|
paint.setColor(mPrefixColor);
|
||||||
|
canvas.drawText(mPrefix, 0, mPrefix.length(), super.getCompoundPaddingLeft(), getBaseline(), paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCompoundPaddingLeft() {
|
public int getCompoundPaddingLeft() {
|
||||||
return super.getCompoundPaddingLeft() + mPrefixRect.width();
|
return super.getCompoundPaddingLeft() + desiredWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefix(CharSequence prefix) {
|
||||||
|
mPrefix = prefix;
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
|
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
// see https://autocrypt.org/level1.html#setup-code
|
||||||
|
public class Numeric9x4PassphraseUtil {
|
||||||
|
public static Passphrase generateNumeric9x4Passphrase() {
|
||||||
|
return generateNumeric9x4Passphrase(new SecureRandom());
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static Passphrase generateNumeric9x4Passphrase(Random r) {
|
||||||
|
StringBuilder code = new StringBuilder(36);
|
||||||
|
for (int i = 0; i < 36; i++) {
|
||||||
|
boolean isBeginningOfBlock = i > 0 && (i % 4) == 0;
|
||||||
|
if (isBeginningOfBlock) {
|
||||||
|
code.append('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
String digit = Integer.toString(r.nextInt(10));
|
||||||
|
code.append(digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Passphrase(code.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern AUTOCRYPT_TRANSFER_CODE = Pattern.compile("(\\d{4}-){8}\\d{4}");
|
||||||
|
|
||||||
|
public static boolean isNumeric9x4Passphrase(Passphrase transferCodeChars) {
|
||||||
|
return isNumeric9x4Passphrase(CharBuffer.wrap(transferCodeChars.getCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNumeric9x4Passphrase(CharSequence code) {
|
||||||
|
return AUTOCRYPT_TRANSFER_CODE.matcher(code).matches();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,459 +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="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">
|
|
||||||
|
|
||||||
<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="ABCD" />
|
|
||||||
|
|
||||||
<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="EFGH" />
|
|
||||||
|
|
||||||
<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="IJKL" />
|
|
||||||
|
|
||||||
<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="MNOP" />
|
|
||||||
|
|
||||||
<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_5"
|
|
||||||
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="QRST" />
|
|
||||||
|
|
||||||
<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_6"
|
|
||||||
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="UVWX" />
|
|
||||||
|
|
||||||
</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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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_5"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:hint="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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_6"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:hint="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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/button_bar_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>
|
|
||||||
@@ -1,459 +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="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">
|
|
||||||
|
|
||||||
<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="ABCD" />
|
|
||||||
|
|
||||||
<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="EFGH" />
|
|
||||||
|
|
||||||
<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="IJKL" />
|
|
||||||
|
|
||||||
<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="MNOP" />
|
|
||||||
|
|
||||||
<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_5"
|
|
||||||
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="QRST" />
|
|
||||||
|
|
||||||
<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_6"
|
|
||||||
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="UVWX" />
|
|
||||||
|
|
||||||
</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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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_5"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:hint="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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_6"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:hint="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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/button_bar_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="horizontal">
|
|
||||||
|
|
||||||
<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>
|
|
||||||
@@ -56,330 +56,9 @@
|
|||||||
android:outAnimation="@anim/fade_out"
|
android:outAnimation="@anim/fade_out"
|
||||||
custom:initialView="1">
|
custom:initialView="1">
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/transfer_code_display" android:id="@+id/transfer_code_display" />
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/transfer_code_input" android:id="@+id/transfer_code_input" />
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:orientation="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="ABCD" />
|
|
||||||
|
|
||||||
<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="EFGH" />
|
|
||||||
|
|
||||||
<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="IJKL" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<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="MNOP" />
|
|
||||||
|
|
||||||
<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_5"
|
|
||||||
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="QRST" />
|
|
||||||
|
|
||||||
<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_6"
|
|
||||||
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="UVWX" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:orientation="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="ABCD"
|
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
|
||||||
android:maxLength="4"
|
|
||||||
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="ABCD"
|
|
||||||
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="ABCD"
|
|
||||||
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>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<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="ABCD"
|
|
||||||
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_5"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:hint="ABCD"
|
|
||||||
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_6"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:hint="ABCD"
|
|
||||||
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>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="14dp"
|
||||||
|
android:paddingTop="14dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/passphrase_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="24dp"
|
||||||
|
android:layout_marginRight="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:text="@string/passphrase_transfer"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
|
||||||
|
<include layout="@layout/transfer_code_input" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="?android:attr/textAppearanceMedium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:text="@string/label_unlock" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
145
OpenKeychain/src/main/res/layout/transfer_code_display.xml
Normal file
145
OpenKeychain/src/main/res/layout/transfer_code_display.xml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="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.
|
||||||
|
-->
|
||||||
|
<org.sufficientlysecure.keychain.ui.widget.PrefixedEditText
|
||||||
|
android:id="@+id/transfer_code_block_1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:enabled="false"
|
||||||
|
custom:prefixColor="@color/md_grey_600"
|
||||||
|
tools:hint="34"
|
||||||
|
tools:prefix="12"
|
||||||
|
tools:text="34"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_4"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_5"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_6"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_7"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_8"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/transfer_code_block_9"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
tools:text="1234" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
138
OpenKeychain/src/main/res/layout/transfer_code_input.xml
Normal file
138
OpenKeychain/src/main/res/layout/transfer_code_input.xml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:showIn="@layout/backup_code_fragment">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<org.sufficientlysecure.keychain.ui.widget.PrefixedEditText
|
||||||
|
android:id="@+id/transfer_code_block_1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
custom:prefixColor="@color/md_grey_600"
|
||||||
|
tools:prefix="12"
|
||||||
|
tools:hint="34"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_4"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_5"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_6"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_7"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_8"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeTextSep" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/transfer_code_block_9"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TransferCodeText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
<declare-styleable name="PrefixedEditText">
|
<declare-styleable name="PrefixedEditText">
|
||||||
<attr name="prefix" format="string" />
|
<attr name="prefix" format="string" />
|
||||||
|
<attr name="prefixColor" format="color" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -102,6 +102,7 @@
|
|||||||
<string name="btn_encrypt_text">"Encrypt text"</string>
|
<string name="btn_encrypt_text">"Encrypt text"</string>
|
||||||
<string name="btn_add_email">"Add additional email address"</string>
|
<string name="btn_add_email">"Add additional email address"</string>
|
||||||
<string name="btn_unlock">"Unlock"</string>
|
<string name="btn_unlock">"Unlock"</string>
|
||||||
|
<string name="btn_proceed">"Proceed"</string>
|
||||||
<string name="btn_add_keyserver">"Add"</string>
|
<string name="btn_add_keyserver">"Add"</string>
|
||||||
<string name="btn_save_default">"Save as default"</string>
|
<string name="btn_save_default">"Save as default"</string>
|
||||||
<string name="btn_saved">"Saved!"</string>
|
<string name="btn_saved">"Saved!"</string>
|
||||||
@@ -333,6 +334,8 @@
|
|||||||
<string name="passphrase_for_any">"Enter password"</string>
|
<string name="passphrase_for_any">"Enter password"</string>
|
||||||
<string name="passphrase_keyboard_hint_alpha">"Switch to alphabetic keyboard"</string>
|
<string name="passphrase_keyboard_hint_alpha">"Switch to alphabetic keyboard"</string>
|
||||||
<string name="passphrase_keyboard_hint_numeric">"Switch to numeric keyboard"</string>
|
<string name="passphrase_keyboard_hint_numeric">"Switch to numeric keyboard"</string>
|
||||||
|
<string name="passphrase_transfer">"Enter transfer code"</string>
|
||||||
|
<string name="passphrase_transfer_autocrypt">"To import this Autocrypt Setup Message, enter transfer code:"</string>
|
||||||
<string name="pin_for">"Enter PIN for '%s'"</string>
|
<string name="pin_for">"Enter PIN for '%s'"</string>
|
||||||
<string name="security_token_pin_for">"Enter PIN to access Security Token for '%s'"</string>
|
<string name="security_token_pin_for">"Enter PIN to access Security Token for '%s'"</string>
|
||||||
<string name="security_token_nfc_text">"Hold Security Token against the NFC marker at the back of your device."</string>
|
<string name="security_token_nfc_text">"Hold Security Token against the NFC marker at the back of your device."</string>
|
||||||
@@ -633,6 +636,7 @@
|
|||||||
<string name="intent_import_key">"Import Key with OpenKeychain"</string>
|
<string name="intent_import_key">"Import Key with OpenKeychain"</string>
|
||||||
<string name="intent_send_encrypt">"Encrypt with OpenKeychain"</string>
|
<string name="intent_send_encrypt">"Encrypt with OpenKeychain"</string>
|
||||||
<string name="intent_send_decrypt">"Decrypt with OpenKeychain"</string>
|
<string name="intent_send_decrypt">"Decrypt with OpenKeychain"</string>
|
||||||
|
<string name="intent_autocrypt_setup">"Import Autocrypt Setup Message"</string>
|
||||||
|
|
||||||
<!-- Remote API -->
|
<!-- Remote API -->
|
||||||
<string name="api_settings_show_info">"Show advanced information"</string>
|
<string name="api_settings_show_info">"Show advanced information"</string>
|
||||||
@@ -1176,6 +1180,8 @@
|
|||||||
<string name="msg_dc_asym">"Found block of asymmetrically encrypted data for key %s"</string>
|
<string name="msg_dc_asym">"Found block of asymmetrically encrypted data for key %s"</string>
|
||||||
<string name="msg_dc_charset">"Found charset header: '%s'"</string>
|
<string name="msg_dc_charset">"Found charset header: '%s'"</string>
|
||||||
<string name="msg_dc_backup_version">"Found backupVersion header: '%s'"</string>
|
<string name="msg_dc_backup_version">"Found backupVersion header: '%s'"</string>
|
||||||
|
<string name="msg_dc_passphrase_format">"Found Passphrase-Format header: '%s'"</string>
|
||||||
|
<string name="msg_dc_passphrase_begin">"Found Passphrase-Begin header: '%s'"</string>
|
||||||
<string name="msg_dc_clear_data">"Processing literal data"</string>
|
<string name="msg_dc_clear_data">"Processing literal data"</string>
|
||||||
<string name="msg_dc_clear_decompress">"Unpacking compressed data"</string>
|
<string name="msg_dc_clear_decompress">"Unpacking compressed data"</string>
|
||||||
<string name="msg_dc_clear_meta_file">"Filename: %s"</string>
|
<string name="msg_dc_clear_meta_file">"Filename: %s"</string>
|
||||||
|
|||||||
@@ -65,4 +65,23 @@
|
|||||||
<item name="android:textSize" tools:ignore="SpUsage">14dp</item>
|
<item name="android:textSize" tools:ignore="SpUsage">14dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="TransferCodeText">
|
||||||
|
<item name="android:gravity">center_vertical</item>
|
||||||
|
<item name="android:singleLine">true</item>
|
||||||
|
<item name="android:hint">1234</item>
|
||||||
|
<item name="android:maxLength">4</item>
|
||||||
|
<item name="android:textColorHint">@android:color/transparent</item>
|
||||||
|
<item name="android:textSize">18sp</item>
|
||||||
|
<item name="android:minHeight">42sp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:typeface">monospace</item>
|
||||||
|
<item name="android:textColor">#000</item>
|
||||||
|
<item name="android:inputType">numberPassword|textVisiblePassword</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TransferCodeTextSep" parent="TransferCodeText">
|
||||||
|
<item name="android:hint"></item>
|
||||||
|
<item name="android:text">-</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ public class BackupOperationTest {
|
|||||||
assertTrue("second keyring has local certification", checkForLocal(mStaticRing2));
|
assertTrue("second keyring has local certification", checkForLocal(mStaticRing2));
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
boolean result = op.exportKeysToStream(new OperationLog(), null, false, out);
|
boolean result = op.exportKeysToStream(new OperationLog(), null, false, true, out);
|
||||||
|
|
||||||
assertTrue("export must be a success", result);
|
assertTrue("export must be a success", result);
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ public class BackupOperationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out = new ByteArrayOutputStream();
|
out = new ByteArrayOutputStream();
|
||||||
result = op.exportKeysToStream(new OperationLog(), null, true, out);
|
result = op.exportKeysToStream(new OperationLog(), null, true, true, out);
|
||||||
|
|
||||||
assertTrue("export must be a success", result);
|
assertTrue("export must be a success", result);
|
||||||
|
|
||||||
@@ -252,7 +252,7 @@ public class BackupOperationTest {
|
|||||||
BackupOperation op = new BackupOperation(spyApplication,
|
BackupOperation op = new BackupOperation(spyApplication,
|
||||||
KeyWritableRepository.create(RuntimeEnvironment.application), null);
|
KeyWritableRepository.create(RuntimeEnvironment.application), null);
|
||||||
|
|
||||||
BackupKeyringParcel parcel = BackupKeyringParcel.createBackupKeyringParcel(
|
BackupKeyringParcel parcel = BackupKeyringParcel.create(
|
||||||
new long[] { mStaticRing1.getMasterKeyId() }, false, false, true, fakeOutputUri);
|
new long[] { mStaticRing1.getMasterKeyId() }, false, false, true, fakeOutputUri);
|
||||||
|
|
||||||
ExportResult result = op.execute(parcel, null);
|
ExportResult result = op.execute(parcel, null);
|
||||||
@@ -309,7 +309,7 @@ public class BackupOperationTest {
|
|||||||
BackupOperation op = new BackupOperation(spyApplication,
|
BackupOperation op = new BackupOperation(spyApplication,
|
||||||
KeyWritableRepository.create(RuntimeEnvironment.application), null);
|
KeyWritableRepository.create(RuntimeEnvironment.application), null);
|
||||||
|
|
||||||
BackupKeyringParcel parcel = BackupKeyringParcel.createBackupKeyringParcel(
|
BackupKeyringParcel parcel = BackupKeyringParcel.create(
|
||||||
new long[] { mStaticRing1.getMasterKeyId() }, false, true, true, fakeOutputUri);
|
new long[] { mStaticRing1.getMasterKeyId() }, false, true, true, fakeOutputUri);
|
||||||
CryptoInputParcel inputParcel = CryptoInputParcel.createCryptoInputParcel(passphrase);
|
CryptoInputParcel inputParcel = CryptoInputParcel.createCryptoInputParcel(passphrase);
|
||||||
ExportResult result = op.execute(parcel, inputParcel);
|
ExportResult result = op.execute(parcel, inputParcel);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
public class Numeric9x4PassphraseUtilTest {
|
||||||
|
private static final int RANDOM_SEED = 12345;
|
||||||
|
private static final String TRANSFER_CODE_3x3x4 = "1018-5452-1972-0624-7325-1126-8153-1997-1535";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateNumeric9x4Passphrase() {
|
||||||
|
Random r = new Random(RANDOM_SEED);
|
||||||
|
|
||||||
|
Passphrase passphrase = Numeric9x4PassphraseUtil.generateNumeric9x4Passphrase(r);
|
||||||
|
|
||||||
|
assertEquals(TRANSFER_CODE_3x3x4, passphrase.toStringUnsafe());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isNumeric9x4Passphrase() {
|
||||||
|
boolean isValidCodeLayout = Numeric9x4PassphraseUtil.isNumeric9x4Passphrase(TRANSFER_CODE_3x3x4);
|
||||||
|
|
||||||
|
assertTrue(isValidCodeLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isNumeric9x4Passphrase_withBadSuffix() {
|
||||||
|
boolean isValidCodeLayout = Numeric9x4PassphraseUtil.isNumeric9x4Passphrase(TRANSFER_CODE_3x3x4 + "x");
|
||||||
|
|
||||||
|
assertFalse(isValidCodeLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user