Merge branch 'master' of github.com:open-keychain/open-keychain

This commit is contained in:
Dominik Schürmann 2014-08-31 20:26:12 +02:00
commit bdf0436c94
21 changed files with 259 additions and 127 deletions

View File

@ -121,14 +121,7 @@ public class ExportHelper {
// Message is received after exporting is done in KeychainIntentService // Message is received after exporting is done in KeychainIntentService
KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity, KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity,
mActivity.getString(R.string.progress_exporting), mActivity.getString(R.string.progress_exporting),
ProgressDialog.STYLE_HORIZONTAL, ProgressDialog.STYLE_HORIZONTAL) {
true,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
mActivity.stopService(intent);
}
}) {
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message); super.handleMessage(message);

View File

@ -33,6 +33,8 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
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.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult; import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult; import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
@ -46,6 +48,7 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class PgpImportExport { public class PgpImportExport {
@ -56,6 +59,7 @@ public class PgpImportExport {
private Context mContext; private Context mContext;
private Progressable mProgressable; private Progressable mProgressable;
private AtomicBoolean mCancelled;
private KeychainServiceListener mKeychainServiceListener; private KeychainServiceListener mKeychainServiceListener;
@ -72,6 +76,14 @@ public class PgpImportExport {
this.mProviderHelper = providerHelper; this.mProviderHelper = providerHelper;
} }
public PgpImportExport(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) {
super();
mContext = context;
mProgressable = progressable;
mProviderHelper = providerHelper;
mCancelled = cancelled;
}
public PgpImportExport(Context context, public PgpImportExport(Context context,
Progressable progressable, KeychainServiceListener keychainListener) { Progressable progressable, KeychainServiceListener keychainListener) {
super(); super();
@ -143,6 +155,11 @@ public class PgpImportExport {
int position = 0; int position = 0;
double progSteps = 100.0 / num; double progSteps = 100.0 / num;
for (ParcelableKeyRing entry : new IterableIterator<ParcelableKeyRing>(entries)) { for (ParcelableKeyRing entry : new IterableIterator<ParcelableKeyRing>(entries)) {
// Has this action been cancelled? If so, don't proceed any further
if (mCancelled != null && mCancelled.get()) {
break;
}
try { try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes()); UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@ -208,9 +225,13 @@ public class PgpImportExport {
} }
} }
if (log.containsWarnings()) { if (log.containsWarnings()) {
resultType |= ImportKeyResult.RESULT_WITH_WARNINGS; resultType |= ImportKeyResult.RESULT_WARNINGS;
} }
} }
if (mCancelled != null && mCancelled.get()) {
log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, 0);
resultType |= ImportKeyResult.RESULT_CANCELLED;
}
return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret); return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret);

View File

@ -73,6 +73,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Stack; 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 * 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 { public class PgpKeyOperation {
private Stack<Progressable> mProgress; private Stack<Progressable> mProgress;
private AtomicBoolean mCancelled;
// most preferred is first // most preferred is first
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ 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) { private void subProgressPush(int from, int to) {
if (mProgress == null) { if (mProgress == null) {
return; return;
@ -450,6 +461,12 @@ public class PgpKeyOperation {
try { 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 { // work on master secret key
PGPPublicKey modifiedPublicKey = masterPublicKey; 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 // 4a. For each subkey change, generate new subkey binding certificate
subProgressPush(50, 60); subProgressPush(50, 60);
for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) { for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {
@ -750,6 +773,12 @@ public class PgpKeyOperation {
subProgressPush(70, 90); subProgressPush(70, 90);
for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) { 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())); progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i); SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent, log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent,
@ -806,6 +835,12 @@ public class PgpKeyOperation {
} }
subProgressPop(); 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 // 6. If requested, change passphrase
if (saveParcel.mNewPassphrase != null) { if (saveParcel.mNewPassphrase != null) {
progress(R.string.progress_modify_passphrase, 90); 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.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper; 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.ConsolidateResult;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult; import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult; import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
@ -72,6 +75,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* This Service contains all important long lasting operations for APG. It receives Intents with * This Service contains all important long lasting operations for APG. It receives Intents with
@ -92,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_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 public static final String ACTION_DELETE_FILE_SECURELY = Constants.INTENT_PREFIX
+ "DELETE_FILE_SECURELY"; + "DELETE_FILE_SECURELY";
@ -110,6 +114,8 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE"; public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
public static final String ACTION_CANCEL = Constants.INTENT_PREFIX + "CANCEL";
/* keys for data bundle */ /* keys for data bundle */
// encrypt, decrypt, import export // encrypt, decrypt, import export
@ -141,8 +147,8 @@ public class KeychainIntentService extends IntentService
public static final String DECRYPT_PASSPHRASE = "passphrase"; public static final String DECRYPT_PASSPHRASE = "passphrase";
// save keyring // save keyring
public static final String SAVE_KEYRING_PARCEL = "save_parcel"; public static final String EDIT_KEYRING_PARCEL = "save_parcel";
public static final String SAVE_KEYRING_PASSPHRASE = "passphrase"; public static final String EDIT_KEYRING_PASSPHRASE = "passphrase";
// delete file securely // delete file securely
public static final String DELETE_FILE = "deleteFile"; public static final String DELETE_FILE = "deleteFile";
@ -196,6 +202,8 @@ public class KeychainIntentService extends IntentService
Messenger mMessenger; Messenger mMessenger;
private boolean mIsCanceled; private boolean mIsCanceled;
// this attribute can possibly merged with the one above? not sure...
private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
public KeychainIntentService() { public KeychainIntentService() {
super("KeychainIntentService"); super("KeychainIntentService");
@ -214,6 +222,10 @@ public class KeychainIntentService extends IntentService
*/ */
@Override @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
// We have not been cancelled! (yet)
mActionCanceled.set(false);
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
if (extras == null) { if (extras == null) {
Log.e(Constants.TAG, "Extras bundle is null!"); Log.e(Constants.TAG, "Extras bundle is null!");
@ -400,21 +412,22 @@ public class KeychainIntentService extends IntentService
} catch (Exception e) { } catch (Exception e) {
sendErrorToHandler(e); sendErrorToHandler(e);
} }
} else if (ACTION_SAVE_KEYRING.equals(action)) { } else if (ACTION_EDIT_KEYRING.equals(action)) {
try { try {
/* Input */ /* Input */
SaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL); SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
if (saveParcel == null) { if (saveParcel == null) {
Log.e(Constants.TAG, "bug: missing save_keyring_parcel in data!"); Log.e(Constants.TAG, "bug: missing save_keyring_parcel in data!");
return; return;
} }
/* Operation */ /* Operation */
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100)); PgpKeyOperation keyOperations =
new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100), mActionCanceled);
EditKeyResult modifyResult; EditKeyResult modifyResult;
if (saveParcel.mMasterKeyId != null) { if (saveParcel.mMasterKeyId != null) {
String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE); String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE);
CanonicalizedSecretKeyRing secRing = CanonicalizedSecretKeyRing secRing =
new ProviderHelper(this).getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId); new ProviderHelper(this).getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
@ -436,6 +449,20 @@ public class KeychainIntentService extends IntentService
UncachedKeyRing ring = modifyResult.getRing(); 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 // Save the keyring. The ProviderHelper is initialized with the previous log
SaveKeyringResult saveResult = new ProviderHelper(this, modifyResult.getLog()) SaveKeyringResult saveResult = new ProviderHelper(this, modifyResult.getLog())
.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100)); .saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
@ -499,12 +526,17 @@ public class KeychainIntentService extends IntentService
} }
ProviderHelper providerHelper = new ProviderHelper(this); ProviderHelper providerHelper = new ProviderHelper(this);
PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this); PgpImportExport pgpImportExport = new PgpImportExport(
this, providerHelper, this, mActionCanceled);
ImportKeyResult result = pgpImportExport.importKeyRings(entries); ImportKeyResult result = pgpImportExport.importKeyRings(entries);
// we do this even on failure or cancellation!
if (result.mSecret > 0) { if (result.mSecret > 0) {
// cannot cancel from here on out!
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_PREVENT_CANCEL);
providerHelper.consolidateDatabaseStep1(this); providerHelper.consolidateDatabaseStep1(this);
} }
// make sure new data is synced into contacts // make sure new data is synced into contacts
ContactSyncAdapterService.requestSync(); ContactSyncAdapterService.requestSync();
@ -612,7 +644,6 @@ public class KeychainIntentService extends IntentService
ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size()); ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size());
for (ImportKeysListEntry entry : entries) { for (ImportKeysListEntry entry : entries) {
Keyserver server; Keyserver server;
if (entry.getOrigin() == null) { if (entry.getOrigin() == null) {
server = new HkpKeyserver(keyServer); server = new HkpKeyserver(keyServer);
@ -874,6 +905,15 @@ public class KeychainIntentService extends IntentService
} }
} }
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_CANCEL.equals(intent.getAction())) {
mActionCanceled.set(true);
return START_NOT_STICKY;
}
return super.onStartCommand(intent, flags, startId);
}
private String getOriginalFilename(Bundle data) throws PgpGeneralException, FileNotFoundException { private String getOriginalFilename(Bundle data) throws PgpGeneralException, FileNotFoundException {
int target = data.getInt(TARGET); int target = data.getInt(TARGET);
switch (target) { switch (target) {

View File

@ -18,7 +18,6 @@
package org.sufficientlysecure.keychain.service; package org.sufficientlysecure.keychain.service;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@ -37,6 +36,7 @@ public class KeychainIntentServiceHandler extends Handler {
public static final int MESSAGE_OKAY = 1; public static final int MESSAGE_OKAY = 1;
public static final int MESSAGE_EXCEPTION = 2; public static final int MESSAGE_EXCEPTION = 2;
public static final int MESSAGE_UPDATE_PROGRESS = 3; public static final int MESSAGE_UPDATE_PROGRESS = 3;
public static final int MESSAGE_PREVENT_CANCEL = 4;
// possible data keys for messages // possible data keys for messages
public static final String DATA_ERROR = "error"; public static final String DATA_ERROR = "error";
@ -60,18 +60,16 @@ public class KeychainIntentServiceHandler extends Handler {
public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,
int progressDialogStyle) { int progressDialogStyle) {
this(activity, progressDialogMessage, progressDialogStyle, false, null); this(activity, progressDialogMessage, progressDialogStyle, false);
} }
public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,
int progressDialogStyle, boolean cancelable, int progressDialogStyle, boolean cancelable) {
OnCancelListener onCancelListener) {
this.mActivity = activity; this.mActivity = activity;
this.mProgressDialogFragment = ProgressDialogFragment.newInstance( this.mProgressDialogFragment = ProgressDialogFragment.newInstance(
progressDialogMessage, progressDialogMessage,
progressDialogStyle, progressDialogStyle,
cancelable, cancelable);
onCancelListener);
} }
public void showProgressDialog(FragmentActivity activity) { public void showProgressDialog(FragmentActivity activity) {
@ -126,6 +124,9 @@ public class KeychainIntentServiceHandler extends Handler {
break; break;
case MESSAGE_PREVENT_CANCEL:
mProgressDialogFragment.setPreventCancel(true);
default: default:
Log.e(Constants.TAG, "unknown handler message!"); Log.e(Constants.TAG, "unknown handler message!");
break; break;

View File

@ -55,13 +55,17 @@ public class OperationResultParcel implements Parcelable {
public static final String EXTRA_RESULT = "operation_result"; public static final String EXTRA_RESULT = "operation_result";
/** Holds the overall result, the number specifying varying degrees of success. The first bit /** Holds the overall result, the number specifying varying degrees of success:
* is 0 on overall success, 1 on overall failure. All other bits may be used for more specific * - The first bit is 0 on overall success, 1 on overall failure
* conditions. */ * - The second bit indicates if the action was cancelled - may still be an error or success!
* - The third bit should be set if the operation succeeded with warnings
* All other bits may be used for more specific conditions. */
final int mResult; final int mResult;
public static final int RESULT_OK = 0; public static final int RESULT_OK = 0;
public static final int RESULT_ERROR = 1; public static final int RESULT_ERROR = 1;
public static final int RESULT_CANCELLED = 2;
public static final int RESULT_WARNINGS = 4;
/// A list of log entries tied to the operation result. /// A list of log entries tied to the operation result.
final OperationLog mLog; final OperationLog mLog;
@ -82,7 +86,11 @@ public class OperationResultParcel implements Parcelable {
} }
public boolean success() { public boolean success() {
return (mResult & 1) == 0; return (mResult & RESULT_ERROR) == 0;
}
public boolean cancelled() {
return (mResult & RESULT_CANCELLED) == RESULT_CANCELLED;
} }
public OperationLog getLog() { public OperationLog getLog() {
@ -147,30 +155,25 @@ public class OperationResultParcel implements Parcelable {
public SuperCardToast createNotify(final Activity activity) { public SuperCardToast createNotify(final Activity activity) {
int resultType = getResult();
String str; String str;
int duration, color; int color;
// Not an overall failure // Not an overall failure
if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) { if (cancelled()) {
color = Style.RED;
str = "operation cancelled!";
} else if (success()) {
if (getLog().containsWarnings()) { if (getLog().containsWarnings()) {
color = Style.ORANGE; color = Style.ORANGE;
} else { } else {
color = Style.GREEN; color = Style.GREEN;
} }
str = "operation succeeded!"; str = "operation succeeded!";
// str = activity.getString(R.string.import_error); // str = activity.getString(R.string.import_error);
} else { } else {
color = Style.RED; color = Style.RED;
str = "operation failed"; str = "operation failed";
// str = activity.getString(R.string.import_error); // str = activity.getString(R.string.import_error);
} }
boolean button = getLog() != null && !getLog().isEmpty(); boolean button = getLog() != null && !getLog().isEmpty();
@ -223,7 +226,8 @@ public class OperationResultParcel implements Parcelable {
*/ */
public static enum LogType { 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 // import public
MSG_IP(R.string.msg_ip), MSG_IP(R.string.msg_ip),
@ -440,6 +444,7 @@ public class OperationResultParcel implements Parcelable {
ERROR, // should occur once at the end of a failed operation ERROR, // should occur once at the end of a failed operation
START, // should occur once at the start of each independent operation START, // should occur once at the start of each independent operation
OK, // should occur once at the end of a successful operation OK, // should occur once at the end of a successful operation
CANCELLED, // should occur once at the end of a cancelled operation
} }
@Override @Override

View File

@ -26,6 +26,7 @@ import android.view.View;
import com.github.johnpersano.supertoasts.SuperCardToast; import com.github.johnpersano.supertoasts.SuperCardToast;
import com.github.johnpersano.supertoasts.SuperToast; import com.github.johnpersano.supertoasts.SuperToast;
import com.github.johnpersano.supertoasts.SuperToast.Duration;
import com.github.johnpersano.supertoasts.util.OnClickWrapper; import com.github.johnpersano.supertoasts.util.OnClickWrapper;
import com.github.johnpersano.supertoasts.util.Style; import com.github.johnpersano.supertoasts.util.Style;
@ -44,16 +45,14 @@ public abstract class OperationResults {
public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret; public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
// At least one new key // At least one new key
public static final int RESULT_OK_NEWKEYS = 2; public static final int RESULT_OK_NEWKEYS = 8;
// At least one updated key // At least one updated key
public static final int RESULT_OK_UPDATED = 4; public static final int RESULT_OK_UPDATED = 16;
// At least one key failed (might still be an overall success) // At least one key failed (might still be an overall success)
public static final int RESULT_WITH_ERRORS = 8; public static final int RESULT_WITH_ERRORS = 32;
// There are warnings in the log
public static final int RESULT_WITH_WARNINGS = 16;
// No keys to import... // No keys to import...
public static final int RESULT_FAIL_NOTHING = 32 + 1; public static final int RESULT_FAIL_NOTHING = 64 + 1;
public boolean isOkBoth() { public boolean isOkBoth() {
return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED)) return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED))
@ -119,15 +118,20 @@ public abstract class OperationResults {
if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) { if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
String withWarnings; String withWarnings;
// Any warnings? duration = Duration.EXTRA_LONG;
if ((resultType & ImportKeyResult.RESULT_WITH_WARNINGS) > 0) {
duration = 0;
color = Style.ORANGE;
withWarnings = activity.getResources().getString(R.string.import_with_warnings);
} else {
duration = SuperToast.Duration.LONG;
color = Style.GREEN; color = Style.GREEN;
withWarnings = ""; withWarnings = "";
// Any warnings?
if ((resultType & ImportKeyResult.RESULT_WARNINGS) > 0) {
duration = 0;
color = Style.ORANGE;
withWarnings += activity.getString(R.string.import_with_warnings);
}
if ((resultType & ImportKeyResult.RESULT_CANCELLED) > 0) {
duration = 0;
color = Style.ORANGE;
withWarnings += activity.getString(R.string.import_with_cancelled);
} }
// New and updated keys // New and updated keys
@ -152,13 +156,14 @@ public abstract class OperationResults {
duration = 0; duration = 0;
color = Style.RED; color = Style.RED;
if (isFailNothing()) { if (isFailNothing()) {
str = activity.getString(R.string.import_error_nothing); str = activity.getString((resultType & ImportKeyResult.RESULT_CANCELLED) > 0
? R.string.import_error_nothing_cancelled
: R.string.import_error_nothing);
} else { } else {
str = activity.getString(R.string.import_error); str = activity.getString(R.string.import_error);
} }
} }
// TODO: externalize into Notify class?
boolean button = getLog() != null && !getLog().isEmpty(); boolean button = getLog() != null && !getLog().isEmpty();
SuperCardToast toast = new SuperCardToast(activity, SuperCardToast toast = new SuperCardToast(activity,
button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD,
@ -243,7 +248,7 @@ public abstract class OperationResults {
} }
// Some old key was updated // Some old key was updated
public static final int UPDATED = 2; public static final int UPDATED = 4;
// Public key was saved // Public key was saved
public static final int SAVED_PUBLIC = 8; public static final int SAVED_PUBLIC = 8;

View File

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

View File

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

View File

@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.nfc.NdefMessage; import android.nfc.NdefMessage;
@ -447,7 +449,8 @@ public class ImportKeysActivity extends ActionBarActivity {
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
this, this,
getString(R.string.progress_importing), getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL) { ProgressDialog.STYLE_HORIZONTAL,
true) {
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message); super.handleMessage(message);

View File

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

View File

@ -21,32 +21,29 @@ import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnKeyListener; import android.content.DialogInterface.OnKeyListener;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
public class ProgressDialogFragment extends DialogFragment { public class ProgressDialogFragment extends DialogFragment {
private static final String ARG_MESSAGE = "message"; private static final String ARG_MESSAGE = "message";
private static final String ARG_STYLE = "style"; private static final String ARG_STYLE = "style";
private static final String ARG_CANCELABLE = "cancelable"; private static final String ARG_CANCELABLE = "cancelable";
private OnCancelListener mOnCancelListener; boolean mCanCancel = false, mPreventCancel = false, mIsCancelled = false;
/** /** Creates new instance of this fragment */
* Creates new instance of this fragment public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable) {
*
* @param message
* @param style
* @param cancelable
* @return
*/
public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable,
OnCancelListener onCancelListener) {
ProgressDialogFragment frag = new ProgressDialogFragment(); ProgressDialogFragment frag = new ProgressDialogFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(ARG_MESSAGE, message); args.putString(ARG_MESSAGE, message);
@ -54,43 +51,33 @@ public class ProgressDialogFragment extends DialogFragment {
args.putBoolean(ARG_CANCELABLE, cancelable); args.putBoolean(ARG_CANCELABLE, cancelable);
frag.setArguments(args); frag.setArguments(args);
frag.mOnCancelListener = onCancelListener;
return frag; return frag;
} }
/** /** Updates progress of dialog */
* Updates progress of dialog
*
* @param messageId
* @param progress
* @param max
*/
public void setProgress(int messageId, int progress, int max) { public void setProgress(int messageId, int progress, int max) {
setProgress(getString(messageId), progress, max); setProgress(getString(messageId), progress, max);
} }
/** /** Updates progress of dialog */
* Updates progress of dialog
*
* @param progress
* @param max
*/
public void setProgress(int progress, int max) { public void setProgress(int progress, int max) {
if (mIsCancelled) {
return;
}
ProgressDialog dialog = (ProgressDialog) getDialog(); ProgressDialog dialog = (ProgressDialog) getDialog();
dialog.setProgress(progress); dialog.setProgress(progress);
dialog.setMax(max); dialog.setMax(max);
} }
/** /** Updates progress of dialog */
* Updates progress of dialog
*
* @param message
* @param progress
* @param max
*/
public void setProgress(String message, int progress, int max) { public void setProgress(String message, int progress, int max) {
if (mIsCancelled) {
return;
}
ProgressDialog dialog = (ProgressDialog) getDialog(); ProgressDialog dialog = (ProgressDialog) getDialog();
dialog.setMessage(message); dialog.setMessage(message);
@ -98,15 +85,6 @@ public class ProgressDialogFragment extends DialogFragment {
dialog.setMax(max); dialog.setMax(max);
} }
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (this.mOnCancelListener != null) {
this.mOnCancelListener.onCancel(dialog);
}
}
/** /**
* Creates dialog * Creates dialog
*/ */
@ -121,41 +99,88 @@ public class ProgressDialogFragment extends DialogFragment {
ProgressDialog dialog = new ProgressDialog(context); ProgressDialog dialog = new ProgressDialog(context);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// We never use the builtin cancel method
dialog.setCancelable(false); dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false); dialog.setCanceledOnTouchOutside(false);
String message = getArguments().getString(ARG_MESSAGE); String message = getArguments().getString(ARG_MESSAGE);
int style = getArguments().getInt(ARG_STYLE); int style = getArguments().getInt(ARG_STYLE);
boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE); mCanCancel = getArguments().getBoolean(ARG_CANCELABLE);
dialog.setMessage(message); dialog.setMessage(message);
dialog.setProgressStyle(style); dialog.setProgressStyle(style);
if (cancelable) { // If this is supposed to be cancelable, add our (custom) cancel mechanic
if (mCanCancel) {
// Just show the button, take care of the onClickListener afterwards (in onStart)
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, dialog.setButton(DialogInterface.BUTTON_NEGATIVE,
activity.getString(R.string.progress_cancel), activity.getString(R.string.progress_cancel), (DialogInterface.OnClickListener) null);
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
} }
// Disable the back button // Disable the back button regardless
OnKeyListener keyListener = new OnKeyListener() { OnKeyListener keyListener = new OnKeyListener() {
@Override @Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mCanCancel) {
((ProgressDialog) dialog).getButton(
DialogInterface.BUTTON_NEGATIVE).performClick();
}
// return true, indicating we handled this
return true; return true;
} }
return false; return false;
} }
}; };
dialog.setOnKeyListener(keyListener); dialog.setOnKeyListener(keyListener);
return dialog; return dialog;
} }
public void setPreventCancel(boolean preventCancel) {
// Don't care if we can't cancel anymore either way!
if (mIsCancelled || ! mCanCancel) {
return;
}
mPreventCancel = preventCancel;
final Button negative = ((ProgressDialog) getDialog()).getButton(DialogInterface.BUTTON_NEGATIVE);
negative.setVisibility(preventCancel ? View.GONE : View.VISIBLE);
}
@Override
public void onStart() {
super.onStart();
// Override the default behavior so the dialog is NOT dismissed on click
final Button negative = ((ProgressDialog) getDialog()).getButton(DialogInterface.BUTTON_NEGATIVE);
negative.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// nvm if we are already cancelled, or weren't able to begin with
if (mIsCancelled || ! mCanCancel) {
return;
}
// Remember this, and don't allow another click
mIsCancelled = true;
negative.setClickable(false);
negative.setTextColor(Color.GRAY);
// Set the progress bar accordingly
ProgressDialog dialog = (ProgressDialog) getDialog();
dialog.setIndeterminate(true);
dialog.setMessage(getString(R.string.progress_cancelling));
// send a cancel message. note that this message will be handled by
// KeychainIntentService.onStartCommand, which runs in this thread,
// not the service one, and will not queue up a command.
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_CANCEL);
getActivity().startService(intent);
}
});
}
} }

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.FixedDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v4.widget.FixedDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true"> android:fillViewport="true">

View File

@ -443,7 +443,7 @@
<!--Consolidate--> <!--Consolidate-->
<!--PassphraseCache--> <!--PassphraseCache-->
<!--unsorted--> <!--unsorted-->
<string name="internal_error">Interner Fehler!</string> <string name="msg_internal_error">Interner Fehler!</string>
<string name="section_certifier_id">Beglaubiger</string> <string name="section_certifier_id">Beglaubiger</string>
<string name="section_cert">Zertifikatdetails</string> <string name="section_cert">Zertifikatdetails</string>
<string name="label_user_id">Identität</string> <string name="label_user_id">Identität</string>

View File

@ -662,7 +662,7 @@
<string name="passp_cache_notif_clear">Limpiar caché</string> <string name="passp_cache_notif_clear">Limpiar caché</string>
<string name="passp_cache_notif_pwd">Contraseña</string> <string name="passp_cache_notif_pwd">Contraseña</string>
<!--unsorted--> <!--unsorted-->
<string name="internal_error">¡Error interno!</string> <string name="msg_internal_error">¡Error interno!</string>
<string name="section_certifier_id">Certificador</string> <string name="section_certifier_id">Certificador</string>
<string name="section_cert">Detalles del certificado</string> <string name="section_cert">Detalles del certificado</string>
<string name="label_user_id">Identidad</string> <string name="label_user_id">Identidad</string>

View File

@ -662,7 +662,7 @@
<string name="passp_cache_notif_clear">Effacer le cache</string> <string name="passp_cache_notif_clear">Effacer le cache</string>
<string name="passp_cache_notif_pwd">Mot de passe</string> <string name="passp_cache_notif_pwd">Mot de passe</string>
<!--unsorted--> <!--unsorted-->
<string name="internal_error">Erreur interne !</string> <string name="msg_internal_error">Erreur interne !</string>
<string name="section_certifier_id">Certificateur</string> <string name="section_certifier_id">Certificateur</string>
<string name="section_cert">Détails du certificat</string> <string name="section_cert">Détails du certificat</string>
<string name="label_user_id">identité</string> <string name="label_user_id">identité</string>

View File

@ -662,7 +662,7 @@
<string name="passp_cache_notif_clear">Pulisci Cache</string> <string name="passp_cache_notif_clear">Pulisci Cache</string>
<string name="passp_cache_notif_pwd">Password</string> <string name="passp_cache_notif_pwd">Password</string>
<!--unsorted--> <!--unsorted-->
<string name="internal_error">Errore interno!</string> <string name="msg_internal_error">Errore interno!</string>
<string name="section_certifier_id">Certificatore</string> <string name="section_certifier_id">Certificatore</string>
<string name="section_cert">Dettagli Certificato</string> <string name="section_cert">Dettagli Certificato</string>
<string name="label_user_id">Identit</string> <string name="label_user_id">Identit</string>

View File

@ -637,7 +637,7 @@
<string name="passp_cache_notif_clear">キャッシュクリア</string> <string name="passp_cache_notif_clear">キャッシュクリア</string>
<string name="passp_cache_notif_pwd">パスワード</string> <string name="passp_cache_notif_pwd">パスワード</string>
<!--unsorted--> <!--unsorted-->
<string name="internal_error">内部エラー!</string> <string name="msg_internal_error">内部エラー!</string>
<string name="section_certifier_id">検証者</string> <string name="section_certifier_id">検証者</string>
<string name="section_cert">証明の詳細</string> <string name="section_cert">証明の詳細</string>
<string name="label_user_id">ユーザID</string> <string name="label_user_id">ユーザID</string>

View File

@ -601,7 +601,7 @@
<string name="passp_cache_notif_clear">Очистити кеш</string> <string name="passp_cache_notif_clear">Очистити кеш</string>
<string name="passp_cache_notif_pwd">Пароль</string> <string name="passp_cache_notif_pwd">Пароль</string>
<!--unsorted--> <!--unsorted-->
<string name="internal_error">Внутрішня помилка!</string> <string name="msg_internal_error">Внутрішня помилка!</string>
<string name="section_certifier_id">Ким підписаний</string> <string name="section_certifier_id">Ким підписаний</string>
<string name="section_cert">Дані сертифікату</string> <string name="section_cert">Дані сертифікату</string>
<string name="label_user_id">Сутність</string> <string name="label_user_id">Сутність</string>

View File

@ -262,6 +262,7 @@
<!-- progress dialogs, usually ending in '…' --> <!-- progress dialogs, usually ending in '…' -->
<string name="progress_done">Done.</string> <string name="progress_done">Done.</string>
<string name="progress_cancel">Cancel</string> <string name="progress_cancel">Cancel</string>
<string name="progress_cancelling">cancelling…</string>
<string name="progress_saving">saving…</string> <string name="progress_saving">saving…</string>
<string name="progress_importing">importing…</string> <string name="progress_importing">importing…</string>
<string name="progress_exporting">exporting…</string> <string name="progress_exporting">exporting…</string>
@ -381,8 +382,10 @@
</plurals> </plurals>
<string name="view_log">View Log</string> <string name="view_log">View Log</string>
<string name="import_error_nothing">Nothing to import.</string> <string name="import_error_nothing">Nothing to import.</string>
<string name="import_error_nothing_cancelled">Import cancelled.</string>
<string name="import_error">Error importing keys!</string> <string name="import_error">Error importing keys!</string>
<string name="import_with_warnings">, with warnings</string> <string name="import_with_warnings">, with warnings</string>
<string name="import_with_cancelled">, until cancelled</string>
<!-- Intent labels --> <!-- Intent labels -->
<string name="intent_decrypt_file">Decrypt File with OpenKeychain</string> <string name="intent_decrypt_file">Decrypt File with OpenKeychain</string>
@ -519,6 +522,9 @@
<!-- LogType log messages. Errors should have _ERROR_ in their name and end with a ! --> <!-- LogType log messages. Errors should have _ERROR_ in their name and end with a ! -->
<string name="msg_internal_error">Internal error!</string>
<string name="msg_cancelled">Operation cancelled.</string>
<!-- Import Public log entries --> <!-- Import Public log entries -->
<string name="msg_ip_apply_batch">Applying insert batch operation.</string> <string name="msg_ip_apply_batch">Applying insert batch operation.</string>
<string name="msg_ip_bad_type_secret">Tried to import secret keyring as public. This is a bug, please file a report!</string> <string name="msg_ip_bad_type_secret">Tried to import secret keyring as public. This is a bug, please file a report!</string>
@ -744,7 +750,6 @@
<string name="passp_cache_notif_pwd">Password</string> <string name="passp_cache_notif_pwd">Password</string>
<!-- unsorted --> <!-- unsorted -->
<string name="internal_error">Internal error!</string>
<string name="section_certifier_id">Certifier</string> <string name="section_certifier_id">Certifier</string>
<string name="section_cert">Certificate Details</string> <string name="section_cert">Certificate Details</string>
<string name="label_user_id">Identity</string> <string name="label_user_id">Identity</string>