add cancel support to edit key action

This commit is contained in:
Vincent Breitmoser
2014-08-31 19:20:08 +02:00
parent d483a8b73e
commit e46bc24079
13 changed files with 92 additions and 33 deletions

View File

@@ -73,6 +73,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class is the single place where ALL operations that actually modify a PGP public or secret
@@ -85,6 +86,7 @@ import java.util.Stack;
*/
public class PgpKeyOperation {
private Stack<Progressable> mProgress;
private AtomicBoolean mCancelled;
// most preferred is first
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
@@ -134,6 +136,15 @@ public class PgpKeyOperation {
}
}
public PgpKeyOperation(Progressable progress, AtomicBoolean cancelled) {
this(progress);
mCancelled = cancelled;
}
private boolean checkCancelled() {
return mCancelled != null && mCancelled.get();
}
private void subProgressPush(int from, int to) {
if (mProgress == null) {
return;
@@ -450,6 +461,12 @@ public class PgpKeyOperation {
try {
// Check if we were cancelled
if (checkCancelled()) {
log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, indent);
return new EditKeyResult(EditKeyResult.RESULT_CANCELLED, log, null);
}
{ // work on master secret key
PGPPublicKey modifiedPublicKey = masterPublicKey;
@@ -640,6 +657,12 @@ public class PgpKeyOperation {
}
// Check if we were cancelled - again
if (checkCancelled()) {
log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, indent);
return new EditKeyResult(EditKeyResult.RESULT_CANCELLED, log, null);
}
// 4a. For each subkey change, generate new subkey binding certificate
subProgressPush(50, 60);
for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {
@@ -750,6 +773,12 @@ public class PgpKeyOperation {
subProgressPush(70, 90);
for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) {
// Check if we were cancelled - again. This operation is expensive so we do it each loop.
if (checkCancelled()) {
log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, indent);
return new EditKeyResult(EditKeyResult.RESULT_CANCELLED, log, null);
}
progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent,
@@ -806,6 +835,12 @@ public class PgpKeyOperation {
}
subProgressPop();
// Check if we were cancelled - again. This operation is expensive so we do it each loop.
if (checkCancelled()) {
log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, indent);
return new EditKeyResult(EditKeyResult.RESULT_CANCELLED, log, null);
}
// 6. If requested, change passphrase
if (saveParcel.mNewPassphrase != null) {
progress(R.string.progress_modify_passphrase, 90);

View File

@@ -54,6 +54,9 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
@@ -93,7 +96,7 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_DECRYPT_METADATA = Constants.INTENT_PREFIX + "DECRYPT_METADATA";
public static final String ACTION_SAVE_KEYRING = Constants.INTENT_PREFIX + "SAVE_KEYRING";
public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING";
public static final String ACTION_DELETE_FILE_SECURELY = Constants.INTENT_PREFIX
+ "DELETE_FILE_SECURELY";
@@ -144,8 +147,8 @@ public class KeychainIntentService extends IntentService
public static final String DECRYPT_PASSPHRASE = "passphrase";
// save keyring
public static final String SAVE_KEYRING_PARCEL = "save_parcel";
public static final String SAVE_KEYRING_PASSPHRASE = "passphrase";
public static final String EDIT_KEYRING_PARCEL = "save_parcel";
public static final String EDIT_KEYRING_PASSPHRASE = "passphrase";
// delete file securely
public static final String DELETE_FILE = "deleteFile";
@@ -409,21 +412,22 @@ public class KeychainIntentService extends IntentService
} catch (Exception e) {
sendErrorToHandler(e);
}
} else if (ACTION_SAVE_KEYRING.equals(action)) {
} else if (ACTION_EDIT_KEYRING.equals(action)) {
try {
/* Input */
SaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL);
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
if (saveParcel == null) {
Log.e(Constants.TAG, "bug: missing save_keyring_parcel in data!");
return;
}
/* Operation */
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100));
PgpKeyOperation keyOperations =
new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100), mActionCanceled);
EditKeyResult modifyResult;
if (saveParcel.mMasterKeyId != null) {
String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE);
CanonicalizedSecretKeyRing secRing =
new ProviderHelper(this).getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
@@ -445,6 +449,20 @@ public class KeychainIntentService extends IntentService
UncachedKeyRing ring = modifyResult.getRing();
// Check if the action was cancelled
if (mActionCanceled.get()) {
OperationLog log = modifyResult.getLog();
// If it wasn't added before, add log entry
if (!modifyResult.cancelled()) {
log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, 0);
}
// If so, just stop without saving
SaveKeyringResult saveResult = new SaveKeyringResult(
SaveKeyringResult.RESULT_CANCELLED, log, null);
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
return;
}
// Save the keyring. The ProviderHelper is initialized with the previous log
SaveKeyringResult saveResult = new ProviderHelper(this, modifyResult.getLog())
.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));

View File

@@ -86,7 +86,11 @@ public class OperationResultParcel implements Parcelable {
}
public boolean success() {
return (mResult & 1) == 0;
return (mResult & RESULT_ERROR) == 0;
}
public boolean cancelled() {
return (mResult & RESULT_CANCELLED) == RESULT_CANCELLED;
}
public OperationLog getLog() {
@@ -151,30 +155,25 @@ public class OperationResultParcel implements Parcelable {
public SuperCardToast createNotify(final Activity activity) {
int resultType = getResult();
String str;
int duration, color;
int color;
// Not an overall failure
if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
if (cancelled()) {
color = Style.RED;
str = "operation cancelled!";
} else if (success()) {
if (getLog().containsWarnings()) {
color = Style.ORANGE;
} else {
color = Style.GREEN;
}
str = "operation succeeded!";
// str = activity.getString(R.string.import_error);
} else {
color = Style.RED;
str = "operation failed";
// str = activity.getString(R.string.import_error);
}
boolean button = getLog() != null && !getLog().isEmpty();
@@ -227,7 +226,8 @@ public class OperationResultParcel implements Parcelable {
*/
public static enum LogType {
INTERNAL_ERROR (R.string.internal_error),
MSG_INTERNAL_ERROR (R.string.msg_internal_error),
MSG_OPERATION_CANCELLED (R.string.msg_cancelled),
// import public
MSG_IP(R.string.msg_ip),
@@ -444,6 +444,7 @@ public class OperationResultParcel implements Parcelable {
ERROR, // should occur once at the end of a failed operation
START, // should occur once at the start of each independent operation
OK, // should occur once at the end of a successful operation
CANCELLED, // should occur once at the end of a cancelled operation
}
@Override

View File

@@ -31,7 +31,6 @@ import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -126,7 +125,7 @@ public class CreateKeyFinalFragment extends Fragment {
private void createKey() {
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
intent.setAction(KeychainIntentService.ACTION_EDIT_KEYRING);
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
@@ -178,7 +177,7 @@ public class CreateKeyFinalFragment extends Fragment {
parcel.mNewPassphrase = mPassphrase;
// get selected key entries
data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel);
data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, parcel);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);

View File

@@ -507,7 +507,8 @@ public class EditKeyFragment extends LoaderFragment implements
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
getString(R.string.progress_saving),
ProgressDialog.STYLE_HORIZONTAL) {
ProgressDialog.STYLE_HORIZONTAL,
true) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
@@ -543,12 +544,12 @@ public class EditKeyFragment extends LoaderFragment implements
// Send all information needed to service to import key in other thread
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
intent.setAction(KeychainIntentService.ACTION_EDIT_KEYRING);
// fill values for this action
Bundle data = new Bundle();
data.putString(KeychainIntentService.SAVE_KEYRING_PASSPHRASE, passphrase);
data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, mSaveKeyringParcel);
data.putString(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase);
data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Create a new Messenger for the communication back
@@ -560,5 +561,6 @@ public class EditKeyFragment extends LoaderFragment implements
// start service with intent
getActivity().startService(intent);
}
}

View File

@@ -192,6 +192,7 @@ public class LogDisplayFragment extends ListFragment implements OnTouchListener
case ERROR: ih.mImg.setBackgroundColor(Color.RED); break;
case START: ih.mImg.setBackgroundColor(Color.GREEN); break;
case OK: ih.mImg.setBackgroundColor(Color.GREEN); break;
case CANCELLED: ih.mImg.setBackgroundColor(Color.RED); break;
}
return convertView;