Merge branch 'master' of github.com:open-keychain/open-keychain
This commit is contained in:
@@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
@@ -90,14 +91,21 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
|
||||
case PIN:
|
||||
case PATTERN:
|
||||
case PASSPHRASE:
|
||||
if (!cryptoInput.hasPassphrase()) {
|
||||
passphrase = cryptoInput.getPassphrase();
|
||||
if (passphrase == null) {
|
||||
try {
|
||||
passphrase = getCachedPassphrase(certificationKey.getKeyId(), certificationKey.getKeyId());
|
||||
} catch (PassphraseCacheInterface.NoSecretKeyException ignored) {
|
||||
// treat as a cache miss for error handling purposes
|
||||
}
|
||||
}
|
||||
|
||||
if (passphrase == null) {
|
||||
return new CertifyResult(log,
|
||||
RequiredInputParcel.createRequiredSignPassphrase(
|
||||
certificationKey.getKeyId(), certificationKey.getKeyId(), null)
|
||||
);
|
||||
}
|
||||
// certification is always with the master key id, so use that one
|
||||
passphrase = cryptoInput.getPassphrase();
|
||||
break;
|
||||
|
||||
case PASSPHRASE_EMPTY:
|
||||
@@ -105,6 +113,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
|
||||
break;
|
||||
|
||||
case DIVERT_TO_CARD:
|
||||
// the unlock operation will succeed for passphrase == null in a divertToCard key
|
||||
passphrase = null;
|
||||
break;
|
||||
|
||||
|
||||
@@ -482,6 +482,7 @@ public abstract class OperationResult implements Parcelable {
|
||||
// secret key modify
|
||||
MSG_MF (LogLevel.START, R.string.msg_mr),
|
||||
MSG_MF_DIVERT (LogLevel.DEBUG, R.string.msg_mf_divert),
|
||||
MSG_MF_ERROR_DIVERT_NEWSUB (LogLevel.ERROR, R.string.msg_mf_error_divert_newsub),
|
||||
MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial),
|
||||
MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode),
|
||||
MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint),
|
||||
@@ -499,6 +500,7 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_MF_ERROR_RESTRICTED(LogLevel.ERROR, R.string.msg_mf_error_restricted),
|
||||
MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary),
|
||||
MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig),
|
||||
MSG_MF_ERROR_SUB_STRIPPED(LogLevel.ERROR, R.string.msg_mf_error_sub_stripped),
|
||||
MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing),
|
||||
MSG_MF_ERROR_CONFLICTING_NFC_COMMANDS(LogLevel.ERROR, R.string.msg_mf_error_conflicting_nfc_commands),
|
||||
MSG_MF_ERROR_DUPLICATE_KEYTOCARD_FOR_SLOT(LogLevel.ERROR, R.string.msg_mf_error_duplicate_keytocard_for_slot),
|
||||
|
||||
@@ -897,18 +897,35 @@ public class PgpKeyOperation {
|
||||
pKey = PGPPublicKey.removeCertification(pKey, sig);
|
||||
}
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
cryptoInput.getPassphrase().getCharArray());
|
||||
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
|
||||
PGPSignature sig = generateSubkeyBindingSignature(
|
||||
getSignatureGenerator(masterSecretKey, cryptoInput),
|
||||
cryptoInput.getSignatureTime(),
|
||||
masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry);
|
||||
PGPPrivateKey subPrivateKey;
|
||||
if (!isDivertToCard(sKey)) {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
cryptoInput.getPassphrase().getCharArray());
|
||||
subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
|
||||
// super special case: subkey is allowed to sign, but isn't available
|
||||
if (subPrivateKey == null) {
|
||||
log.add(LogType.MSG_MF_ERROR_SUB_STRIPPED,
|
||||
indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
} else {
|
||||
subPrivateKey = null;
|
||||
}
|
||||
try {
|
||||
PGPSignature sig = generateSubkeyBindingSignature(
|
||||
getSignatureGenerator(masterSecretKey, cryptoInput),
|
||||
cryptoInput.getSignatureTime(), masterPublicKey, masterPrivateKey,
|
||||
getSignatureGenerator(sKey, cryptoInput), subPrivateKey,
|
||||
pKey, flags, expiry);
|
||||
|
||||
// generate and add new signature
|
||||
pKey = PGPPublicKey.addCertification(pKey, sig);
|
||||
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
|
||||
// generate and add new signature
|
||||
pKey = PGPPublicKey.addCertification(pKey, sig);
|
||||
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
@@ -959,6 +976,11 @@ public class PgpKeyOperation {
|
||||
log.add(LogType.MSG_MF_SUBKEY_NEW, indent,
|
||||
KeyFormattingUtils.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve) );
|
||||
|
||||
if (isDivertToCard(masterSecretKey)) {
|
||||
log.add(LogType.MSG_MF_ERROR_DIVERT_NEWSUB, indent +1);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
|
||||
if (add.mExpiry == null) {
|
||||
log.add(LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
@@ -987,7 +1009,8 @@ public class PgpKeyOperation {
|
||||
PGPSignature cert = generateSubkeyBindingSignature(
|
||||
getSignatureGenerator(masterSecretKey, cryptoInput),
|
||||
cryptoInput.getSignatureTime(),
|
||||
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
|
||||
masterPublicKey, masterPrivateKey,
|
||||
getSignatureGenerator(pKey, cryptoInput, false), keyPair.getPrivateKey(), pKey,
|
||||
add.mFlags, add.mExpiry);
|
||||
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
@@ -1402,22 +1425,27 @@ public class PgpKeyOperation {
|
||||
static PGPSignatureGenerator getSignatureGenerator(
|
||||
PGPSecretKey secretKey, CryptoInputParcel cryptoInput) {
|
||||
|
||||
PGPContentSignerBuilder builder;
|
||||
|
||||
S2K s2k = secretKey.getS2K();
|
||||
if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
|
||||
&& s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
|
||||
boolean isDivertToCard = s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
|
||||
&& s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD;
|
||||
|
||||
return getSignatureGenerator(secretKey.getPublicKey(), cryptoInput, isDivertToCard);
|
||||
}
|
||||
|
||||
static PGPSignatureGenerator getSignatureGenerator(
|
||||
PGPPublicKey pKey, CryptoInputParcel cryptoInput, boolean divertToCard) {
|
||||
|
||||
PGPContentSignerBuilder builder;
|
||||
if (divertToCard) {
|
||||
// use synchronous "NFC based" SignerBuilder
|
||||
builder = new NfcSyncPGPContentSignerBuilder(
|
||||
secretKey.getPublicKey().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
|
||||
secretKey.getKeyID(), cryptoInput.getCryptoData())
|
||||
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
|
||||
pKey.getKeyID(), cryptoInput.getCryptoData())
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
} else {
|
||||
// content signer based on signing key algorithm and chosen hash algorithm
|
||||
builder = new JcaPGPContentSignerBuilder(
|
||||
secretKey.getPublicKey().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
}
|
||||
|
||||
@@ -1524,7 +1552,8 @@ public class PgpKeyOperation {
|
||||
static PGPSignature generateSubkeyBindingSignature(
|
||||
PGPSignatureGenerator sGen, Date creationTime,
|
||||
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
|
||||
PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
|
||||
PGPSignatureGenerator subSigGen, PGPPrivateKey subPrivateKey, PGPPublicKey pKey,
|
||||
int flags, long expiry)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
|
||||
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
@@ -1534,10 +1563,6 @@ public class PgpKeyOperation {
|
||||
// cross-certify signing keys
|
||||
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
|
||||
subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
|
||||
subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
|
||||
PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
|
||||
|
||||
@@ -53,7 +53,7 @@ import java.io.IOException;
|
||||
*/
|
||||
public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
private static final String DATABASE_NAME = "openkeychain.db";
|
||||
private static final int DATABASE_VERSION = 10;
|
||||
private static final int DATABASE_VERSION = 11;
|
||||
static Boolean apgHack = false;
|
||||
private Context mContext;
|
||||
|
||||
@@ -274,6 +274,12 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
db.execSQL(CREATE_CERTS);
|
||||
case 10:
|
||||
// do nothing here, just consolidate
|
||||
case 11:
|
||||
db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
|
||||
if (oldVersion == 10) {
|
||||
// no consolidate if we are updating from 10, we're just here for the api_accounts fix
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -297,10 +303,11 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
// It's the Java way =(
|
||||
String[] dbs = context.databaseList();
|
||||
for (String db : dbs) {
|
||||
if (db.equals("apg.db")) {
|
||||
if ("apg.db".equals(db)) {
|
||||
hasApgDb = true;
|
||||
} else if (db.equals("apg_old.db")) {
|
||||
} else if ("apg_old.db".equals(db)) {
|
||||
Log.d(Constants.TAG, "Found apg_old.db, delete it!");
|
||||
// noinspection ResultOfMethodCallIgnored - if it doesn't happen, it doesn't happen.
|
||||
context.getDatabasePath("apg_old.db").delete();
|
||||
}
|
||||
}
|
||||
@@ -384,7 +391,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// delete old database
|
||||
// noinspection ResultOfMethodCallIgnored - not much we can do if this doesn't work
|
||||
context.getDatabasePath("apg.db").delete();
|
||||
}
|
||||
|
||||
@@ -416,6 +423,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
} else {
|
||||
in = context.getDatabasePath(DATABASE_NAME);
|
||||
out = context.getDatabasePath("debug_backup.db");
|
||||
// noinspection ResultOfMethodCallIgnored - this is a pure debug feature, anyways
|
||||
out.createNewFile();
|
||||
}
|
||||
if (!in.canRead()) {
|
||||
|
||||
@@ -324,16 +324,15 @@ public class CertifyKeyFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(CertifyResult result) {
|
||||
public void onQueuedOperationSuccess(CertifyResult result) {
|
||||
// protected by Queueing*Fragment
|
||||
Activity activity = getActivity();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(CertifyResult.EXTRA_RESULT, result);
|
||||
getActivity().setResult(Activity.RESULT_OK, intent);
|
||||
getActivity().finish();
|
||||
}
|
||||
activity.setResult(Activity.RESULT_OK, intent);
|
||||
activity.finish();
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationCancelled() {
|
||||
super.onCryptoOperationCancelled();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -225,6 +225,33 @@ public class CreateKeyFinalFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle queued actions
|
||||
|
||||
if (mQueuedFinishResult != null) {
|
||||
finishWithResult(mQueuedFinishResult);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mQueuedDisplayResult != null) {
|
||||
try {
|
||||
displayResult(mQueuedDisplayResult);
|
||||
} finally {
|
||||
// clear after operation, note that this may drop the operation if it didn't
|
||||
// work when called from here!
|
||||
mQueuedDisplayResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (mQueuedSaveKeyResult != null) {
|
||||
try {
|
||||
uploadKey(mQueuedSaveKeyResult);
|
||||
} finally {
|
||||
// see above
|
||||
mQueuedSaveKeyResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createKey() {
|
||||
@@ -433,35 +460,4 @@ public class CreateKeyFinalFragment extends Fragment {
|
||||
activity.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
// there may be queued actions from when we weren't attached to an activity!
|
||||
|
||||
if (mQueuedFinishResult != null) {
|
||||
finishWithResult(mQueuedFinishResult);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mQueuedDisplayResult != null) {
|
||||
try {
|
||||
displayResult(mQueuedDisplayResult);
|
||||
} finally {
|
||||
// clear after operation, note that this may drop the operation if it didn't
|
||||
// work when called from here!
|
||||
mQueuedDisplayResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (mQueuedSaveKeyResult != null) {
|
||||
try {
|
||||
uploadKey(mQueuedSaveKeyResult);
|
||||
} finally {
|
||||
// see above
|
||||
mQueuedSaveKeyResult = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
@@ -39,7 +40,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment;
|
||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.ParcelableProxy;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
@@ -47,7 +48,7 @@ import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
|
||||
|
||||
|
||||
public class CreateYubiKeyImportFragment
|
||||
extends CryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
|
||||
extends QueueingCryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
|
||||
implements NfcListenerFragment {
|
||||
|
||||
private static final String ARG_FINGERPRINT = "fingerprint";
|
||||
@@ -246,14 +247,17 @@ public class CreateYubiKeyImportFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||
public void onQueuedOperationSuccess(ImportKeyResult result) {
|
||||
long[] masterKeyIds = result.getImportedMasterKeyIds();
|
||||
if (masterKeyIds.length == 0) {
|
||||
super.onCryptoOperationError(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(getActivity(), ViewKeyActivity.class);
|
||||
// null-protected from Queueing*Fragment
|
||||
Activity activity = getActivity();
|
||||
|
||||
Intent intent = new Intent(activity, ViewKeyActivity.class);
|
||||
// use the imported masterKeyId, not the one from the yubikey, because
|
||||
// that one might* just have been a subkey of the imported key
|
||||
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyIds[0]));
|
||||
@@ -262,6 +266,6 @@ public class CreateYubiKeyImportFragment
|
||||
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
|
||||
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,7 @@ public class DecryptActivity extends BaseActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setFullScreenDialogClose(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}, false);
|
||||
setFullScreenDialogClose(Activity.RESULT_CANCELED, false);
|
||||
|
||||
// Handle intent actions
|
||||
handleActions(savedInstanceState, getIntent());
|
||||
|
||||
@@ -66,10 +66,10 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
|
||||
// this import NEEDS to be above the ViewModel one, or it won't compile! (as of 06/06/15)
|
||||
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder;
|
||||
import org.sufficientlysecure.keychain.ui.DecryptListFragment.DecryptFilesAdapter.ViewModel;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
|
||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
@@ -80,7 +80,7 @@ import org.sufficientlysecure.keychain.util.ParcelableHashMap;
|
||||
|
||||
|
||||
public class DecryptListFragment
|
||||
extends CryptoOperationFragment<PgpDecryptVerifyInputParcel,DecryptVerifyResult>
|
||||
extends QueueingCryptoOperationFragment<PgpDecryptVerifyInputParcel,DecryptVerifyResult>
|
||||
implements OnMenuItemClickListener {
|
||||
|
||||
public static final String ARG_INPUT_URIS = "input_uris";
|
||||
@@ -195,15 +195,6 @@ public class DecryptListFragment
|
||||
cryptoOperation();
|
||||
}
|
||||
|
||||
private String removeEncryptedAppend(String name) {
|
||||
if (name.endsWith(Constants.FILE_EXTENSION_ASC)
|
||||
|| name.endsWith(Constants.FILE_EXTENSION_PGP_MAIN)
|
||||
|| name.endsWith(Constants.FILE_EXTENSION_PGP_ALTERNATE)) {
|
||||
return name.substring(0, name.length() - 4);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private void askForOutputFilename(Uri inputUri, String originalFilename, String mimeType) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
File file = new File(inputUri.getPath());
|
||||
@@ -257,7 +248,7 @@ public class DecryptListFragment
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void onCryptoOperationError(DecryptVerifyResult result) {
|
||||
public void onQueuedOperationError(DecryptVerifyResult result) {
|
||||
final Uri uri = mCurrentInputUri;
|
||||
mCurrentInputUri = null;
|
||||
|
||||
@@ -267,7 +258,7 @@ public class DecryptListFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(DecryptVerifyResult result) {
|
||||
public void onQueuedOperationSuccess(DecryptVerifyResult result) {
|
||||
Uri uri = mCurrentInputUri;
|
||||
mCurrentInputUri = null;
|
||||
|
||||
|
||||
@@ -41,13 +41,7 @@ public class DisplayTextActivity extends BaseActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setFullScreenDialogClose(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}, false);
|
||||
setFullScreenDialogClose(Activity.RESULT_CANCELED, false);
|
||||
|
||||
// Handle intent actions
|
||||
handleActions(savedInstanceState, getIntent());
|
||||
|
||||
@@ -57,7 +57,7 @@ import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment;
|
||||
@@ -68,7 +68,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||
|
||||
public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel, OperationResult>
|
||||
public class EditKeyFragment extends QueueingCryptoOperationFragment<SaveKeyringParcel, OperationResult>
|
||||
implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
public static final String ARG_DATA_URI = "uri";
|
||||
@@ -192,7 +192,7 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
|
||||
private void loadData(Uri dataUri) {
|
||||
mDataUri = dataUri;
|
||||
|
||||
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
|
||||
Log.i(Constants.TAG, "mDataUri: " + mDataUri);
|
||||
|
||||
// load the secret key ring. we do verify here that the passphrase is correct, so cached won't do
|
||||
try {
|
||||
@@ -618,13 +618,16 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(OperationResult result) {
|
||||
public void onQueuedOperationSuccess(OperationResult result) {
|
||||
|
||||
// null-protected from Queueing*Fragment
|
||||
Activity activity = getActivity();
|
||||
|
||||
// if good -> finish, return result to showkey and display there!
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(OperationResult.EXTRA_RESULT, result);
|
||||
getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
|
||||
getActivity().finish();
|
||||
activity.setResult(EditKeyActivity.RESULT_OK, intent);
|
||||
activity.finish();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -41,12 +42,7 @@ public class EncryptFilesActivity extends EncryptActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setFullScreenDialogClose(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
}, false);
|
||||
setFullScreenDialogClose(Activity.RESULT_OK, false);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
|
||||
@@ -387,13 +387,10 @@ public class EncryptFilesFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(final SignEncryptResult result) {
|
||||
public void onQueuedOperationSuccess(final SignEncryptResult result) {
|
||||
|
||||
// protected by Queueing*Fragment
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity == null) {
|
||||
// it's gone, there's nothing we can do here
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDeleteAfterEncrypt) {
|
||||
// TODO make behavior coherent here
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
@@ -39,12 +40,7 @@ public class EncryptTextActivity extends EncryptActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setFullScreenDialogClose(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
}, false);
|
||||
setFullScreenDialogClose(Activity.RESULT_OK, false);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
|
||||
@@ -331,7 +331,7 @@ public class EncryptTextFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(SignEncryptResult result) {
|
||||
public void onQueuedOperationSuccess(SignEncryptResult result) {
|
||||
|
||||
if (mShareAfterEncrypt) {
|
||||
// Share encrypted message/file
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -95,6 +96,8 @@ public class ImportKeysActivity extends BaseNfcActivity
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setFullScreenDialogClose(Activity.RESULT_CANCELED, true);
|
||||
|
||||
mProxyPrefs = Preferences.getPreferences(this).getProxyPrefs();
|
||||
|
||||
mImportButton = findViewById(R.id.import_import);
|
||||
|
||||
@@ -257,7 +257,6 @@ public class ImportKeysProxyActivity extends FragmentActivity
|
||||
Intent data = new Intent();
|
||||
data.putExtras(returnData);
|
||||
returnResult(data);
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,7 +31,6 @@ import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Handler.Callback;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.provider.ContactsContract;
|
||||
@@ -57,7 +56,6 @@ import com.getbase.floatingactionbutton.FloatingActionButton;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
@@ -67,10 +65,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
|
||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||
@@ -102,6 +97,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
static final int REQUEST_QR_FINGERPRINT = 1;
|
||||
static final int REQUEST_DELETE = 2;
|
||||
static final int REQUEST_EXPORT = 3;
|
||||
static final int REQUEST_CERTIFY = 4;
|
||||
|
||||
public static final String EXTRA_DISPLAY_RESULT = "display_result";
|
||||
|
||||
ProviderHelper mProviderHelper;
|
||||
@@ -158,6 +155,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mProviderHelper = new ProviderHelper(this);
|
||||
mOperationHelper = new CryptoOperationHelper<>(this, this, null);
|
||||
|
||||
setTitle(null);
|
||||
|
||||
@@ -382,37 +380,14 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
Intent intent = new Intent(this, CertifyFingerprintActivity.class);
|
||||
intent.setData(dataUri);
|
||||
|
||||
startCertifyIntent(intent);
|
||||
startActivityForResult(intent, REQUEST_CERTIFY);
|
||||
}
|
||||
|
||||
private void certifyImmediate() {
|
||||
Intent intent = new Intent(this, CertifyKeyActivity.class);
|
||||
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId});
|
||||
|
||||
startCertifyIntent(intent);
|
||||
}
|
||||
|
||||
private void startCertifyIntent(Intent intent) {
|
||||
// Message is received after signing is done in KeychainService
|
||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
Bundle data = message.getData();
|
||||
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
|
||||
|
||||
result.createNotify(ViewKeyActivity.this).show();
|
||||
}
|
||||
}
|
||||
};
|
||||
// Create a new Messenger for the communication back
|
||||
Messenger messenger = new Messenger(saveHandler);
|
||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
||||
|
||||
startActivityForResult(intent, 0);
|
||||
startActivityForResult(intent, REQUEST_CERTIFY);
|
||||
}
|
||||
|
||||
private void showQrCodeDialog() {
|
||||
@@ -482,49 +457,58 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (mOperationHelper != null) {
|
||||
mOperationHelper.handleActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) {
|
||||
|
||||
// If there is an EXTRA_RESULT, that's an error. Just show it.
|
||||
if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
result.createNotify(this).show();
|
||||
return;
|
||||
}
|
||||
|
||||
String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
|
||||
if (fp == null) {
|
||||
Notify.create(this, "Error scanning fingerprint!",
|
||||
Notify.LENGTH_LONG, Notify.Style.ERROR).show();
|
||||
return;
|
||||
}
|
||||
if (mFingerprint.equalsIgnoreCase(fp)) {
|
||||
certifyImmediate();
|
||||
} else {
|
||||
Notify.create(this, "Fingerprints did not match!",
|
||||
Notify.LENGTH_LONG, Notify.Style.ERROR).show();
|
||||
}
|
||||
|
||||
if (mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) {
|
||||
deleteKey();
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) {
|
||||
exportToFile(mDataUri, mProviderHelper);
|
||||
switch (requestCode) {
|
||||
case REQUEST_QR_FINGERPRINT: {
|
||||
|
||||
// If there is an EXTRA_RESULT, that's an error. Just show it.
|
||||
if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
result.createNotify(this).show();
|
||||
return;
|
||||
}
|
||||
|
||||
String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
|
||||
if (fp == null) {
|
||||
Notify.create(this, R.string.error_scan_fp, Notify.LENGTH_LONG, Style.ERROR).show();
|
||||
return;
|
||||
}
|
||||
if (mFingerprint.equalsIgnoreCase(fp)) {
|
||||
certifyImmediate();
|
||||
} else {
|
||||
Notify.create(this, R.string.error_scan_match, Notify.LENGTH_LONG, Style.ERROR).show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case REQUEST_DELETE: {
|
||||
deleteKey();
|
||||
return;
|
||||
}
|
||||
|
||||
case REQUEST_EXPORT: {
|
||||
exportToFile(mDataUri, mProviderHelper);
|
||||
return;
|
||||
}
|
||||
|
||||
case REQUEST_CERTIFY: {
|
||||
if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
result.createNotify(this).show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
result.createNotify(this).show();
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -863,6 +847,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
mActionNfc.setVisibility(View.GONE);
|
||||
}
|
||||
mFab.setVisibility(View.VISIBLE);
|
||||
// noinspection deprecation (no getDrawable with theme at current minApi level 15!)
|
||||
mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp));
|
||||
} else {
|
||||
mActionEncryptFile.setVisibility(View.VISIBLE);
|
||||
@@ -952,7 +937,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
mKeyserver = cloudPrefs.keyserver;
|
||||
}
|
||||
|
||||
mOperationHelper = new CryptoOperationHelper<>(this, this, null);
|
||||
mOperationHelper.cryptoOperation();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -39,12 +40,12 @@ import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
|
||||
|
||||
public class ViewKeyYubiKeyFragment
|
||||
extends CryptoOperationFragment<PromoteKeyringParcel, PromoteKeyResult>
|
||||
extends QueueingCryptoOperationFragment<PromoteKeyringParcel, PromoteKeyResult>
|
||||
implements LoaderCallbacks<Cursor> {
|
||||
|
||||
public static final String ARG_MASTER_KEY_ID = "master_key_id";
|
||||
@@ -76,7 +77,7 @@ public class ViewKeyYubiKeyFragment
|
||||
}
|
||||
|
||||
public ViewKeyYubiKeyFragment() {
|
||||
super(R.string.progress_processing);
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -214,7 +215,8 @@ public class ViewKeyYubiKeyFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(PromoteKeyResult result) {
|
||||
public void onQueuedOperationSuccess(PromoteKeyResult result) {
|
||||
result.createNotify(getActivity()).show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,9 +87,7 @@ public abstract class BaseActivity extends AppCompatActivity {
|
||||
mToolbar.setNavigationOnClickListener(cancelOnClickListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close button only
|
||||
*/
|
||||
/** Close button only */
|
||||
protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener, boolean white) {
|
||||
if (white) {
|
||||
setActionBarIcon(R.drawable.ic_close_white_24dp);
|
||||
@@ -104,6 +102,17 @@ public abstract class BaseActivity extends AppCompatActivity {
|
||||
setFullScreenDialogClose(cancelOnClickListener, true);
|
||||
}
|
||||
|
||||
/** Close button only, with finish-action and given return status, white. */
|
||||
protected void setFullScreenDialogClose(final int result, boolean white) {
|
||||
setFullScreenDialogClose(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setResult(result);
|
||||
finish();
|
||||
}
|
||||
}, white);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflate custom design with two buttons using drawables.
|
||||
* This does not conform to the Material Design Guidelines, but we deviate here as this is used
|
||||
|
||||
@@ -4,12 +4,11 @@ package org.sufficientlysecure.keychain.ui.base;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
|
||||
|
||||
public abstract class CachingCryptoOperationFragment <T extends Parcelable, S extends OperationResult>
|
||||
extends CryptoOperationFragment<T, S> {
|
||||
extends QueueingCryptoOperationFragment<T, S> {
|
||||
|
||||
public static final String ARG_CACHED_ACTIONS = "cached_actions";
|
||||
|
||||
@@ -32,12 +31,14 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable, S ex
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationSuccess(S result) {
|
||||
public void onQueuedOperationSuccess(S result) {
|
||||
super.onCryptoOperationSuccess(result);
|
||||
mCachedActionsParcel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCryptoOperationError(S result) {
|
||||
public void onQueuedOperationError(S result) {
|
||||
super.onCryptoOperationError(result);
|
||||
mCachedActionsParcel = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
* @see KeychainService
|
||||
*
|
||||
*/
|
||||
public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
|
||||
abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
|
||||
extends Fragment implements CryptoOperationHelper.Callback<T, S> {
|
||||
|
||||
final private CryptoOperationHelper<T, S> mOperationHelper;
|
||||
|
||||
@@ -208,12 +208,9 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void dismissProgress() {
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.sufficientlysecure.keychain.ui.base;
|
||||
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
|
||||
|
||||
/** CryptoOperationFragment which calls crypto operation results only while
|
||||
* attached to Activity.
|
||||
*
|
||||
* This subclass of CryptoOperationFragment substitutes the onCryptoOperation*
|
||||
* methods for onQueuedOperation* ones, which are ensured to be called while
|
||||
* the fragment is attached to an Activity, possibly delaying the call until
|
||||
* the Fragment is re-attached.
|
||||
*
|
||||
* TODO merge this functionality into CryptoOperationFragment?
|
||||
*
|
||||
* @see CryptoOperationFragment
|
||||
*/
|
||||
public abstract class QueueingCryptoOperationFragment<T extends Parcelable, S extends OperationResult>
|
||||
extends CryptoOperationFragment<T,S> {
|
||||
|
||||
public static final String ARG_QUEUED_RESULT = "queued_result";
|
||||
private S mQueuedResult;
|
||||
|
||||
public QueueingCryptoOperationFragment() {
|
||||
super();
|
||||
}
|
||||
|
||||
public QueueingCryptoOperationFragment(Integer initialProgressMsg) {
|
||||
super(initialProgressMsg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
if (mQueuedResult != null) {
|
||||
try {
|
||||
if (mQueuedResult.success()) {
|
||||
onQueuedOperationSuccess(mQueuedResult);
|
||||
} else {
|
||||
onQueuedOperationError(mQueuedResult);
|
||||
}
|
||||
} finally {
|
||||
mQueuedResult = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putParcelable(ARG_QUEUED_RESULT, mQueuedResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mQueuedResult = savedInstanceState.getParcelable(ARG_QUEUED_RESULT);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onQueuedOperationSuccess(S result);
|
||||
|
||||
public void onQueuedOperationError(S result) {
|
||||
super.onCryptoOperationError(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void onCryptoOperationSuccess(S result) {
|
||||
if (getActivity() == null) {
|
||||
mQueuedResult = result;
|
||||
return;
|
||||
}
|
||||
onQueuedOperationSuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void onCryptoOperationError(S result) {
|
||||
if (getActivity() == null) {
|
||||
mQueuedResult = result;
|
||||
return;
|
||||
}
|
||||
onQueuedOperationError(result);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -36,6 +37,8 @@ import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
@@ -72,16 +75,18 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
|
||||
/**
|
||||
* Creates dialog
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Activity activity = getActivity();
|
||||
Activity activity = getActivity();
|
||||
|
||||
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
|
||||
long creation = getArguments().getLong(ARG_CREATION);
|
||||
long expiry = getArguments().getLong(ARG_EXPIRY);
|
||||
|
||||
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
final Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
creationCal.setTime(new Date(creation * 1000));
|
||||
final Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expiryCal.setTime(new Date(expiry * 1000));
|
||||
|
||||
// date picker works with default time zone, we need to convert from UTC to default timezone
|
||||
@@ -175,10 +180,13 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
|
||||
selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
long numDays = (selectedCal.getTimeInMillis() / 86400000)
|
||||
- (expiryCal.getTimeInMillis() / 86400000);
|
||||
- (creationCal.getTimeInMillis() / 86400000);
|
||||
if (numDays <= 0) {
|
||||
Log.e(Constants.TAG, "Should not happen! Expiry num of days <= 0!");
|
||||
throw new RuntimeException();
|
||||
Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
Notify.create(activity, R.string.error_expiry_past, Style.ERROR).show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
expiry = selectedCal.getTime().getTime() / 1000;
|
||||
}
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
<!-- modifySecretKeyRing -->
|
||||
<string name="msg_mr">"Modifying keyring %s"</string>
|
||||
<string name="msg_mf_divert">"Will divert to smart card for crypto operations"</string>
|
||||
<string name="msg_mf_error_divert_newsub">"Creation of new subkeys is not supported for 'divert-to-card' primary keys!"</string>
|
||||
<string name="msg_mf_error_divert_serial">"The serial number of a 'divert-to-card' key must be 16 bytes! This is a programming error, please file a bug report!"</string>
|
||||
<string name="msg_mf_error_encode">"Encoding exception!"</string>
|
||||
<string name="msg_mf_error_fingerprint">"Actual key fingerprint does not match the expected one!"</string>
|
||||
@@ -991,6 +992,7 @@
|
||||
<string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string>
|
||||
<string name="msg_mf_error_pgp">"Internal OpenPGP error!"</string>
|
||||
<string name="msg_mf_error_sig">"Signature exception!"</string>
|
||||
<string name="msg_mf_error_sub_stripped">"Cannot modify stripped subkey %s!"</string>
|
||||
<string name="msg_mf_error_subkey_missing">"Tried to operate on missing subkey %s!"</string>
|
||||
<string name="msg_mf_error_conflicting_nfc_commands">"Cannot move key to smart card in same operation that creates an on-card signature."</string>
|
||||
<string name="msg_mf_error_duplicate_keytocard_for_slot">"Smart card supports only one slot per key type."</string>
|
||||
@@ -1432,5 +1434,8 @@
|
||||
<string name="file_delete_exception">"Original file could not be deleted!"</string>
|
||||
<string name="error_clipboard_empty">"Clipboard is empty!"</string>
|
||||
<string name="error_clipboard_copy">"Error copying data to clipboard!"</string>
|
||||
<string name="error_scan_fp">"Error scanning fingerprint!"</string>
|
||||
<string name="error_scan_match">"Fingerprints did not match!"</string>
|
||||
<string name="error_expiry_past">"Expiry date is in the past!"</string>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user