diff options
| author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-08-31 20:26:12 +0200 | 
|---|---|---|
| committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-08-31 20:26:12 +0200 | 
| commit | bdf0436c9494f25cd1efaa64b6eb180b6d2673d6 (patch) | |
| tree | 5f928c1949c92ee0ee86b60276a5c5c792868e8d /OpenKeychain | |
| parent | 5e7eed239ffc26f2d78b29c0f6dd3772f49dc4e9 (diff) | |
| parent | e9a2f256b9324cc898061d2a2ebde18446ce1dd1 (diff) | |
| download | open-keychain-bdf0436c9494f25cd1efaa64b6eb180b6d2673d6.tar.gz open-keychain-bdf0436c9494f25cd1efaa64b6eb180b6d2673d6.tar.bz2 open-keychain-bdf0436c9494f25cd1efaa64b6eb180b6d2673d6.zip  | |
Merge branch 'master' of github.com:open-keychain/open-keychain
Diffstat (limited to 'OpenKeychain')
21 files changed, 259 insertions, 127 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java index bcd57b290..f065dbc6d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java @@ -121,14 +121,7 @@ public class ExportHelper {          // Message is received after exporting is done in KeychainIntentService          KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity,                  mActivity.getString(R.string.progress_exporting), -                ProgressDialog.STYLE_HORIZONTAL, -                true, -                new DialogInterface.OnCancelListener() { -                                @Override -                                public void onCancel(DialogInterface dialogInterface) { -                                    mActivity.stopService(intent); -                                } -        }) { +                ProgressDialog.STYLE_HORIZONTAL) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index 0bc3ac0ab..f5b2280c9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -33,6 +33,8 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper;  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.OperationResults.ImportKeyResult;  import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult; @@ -46,6 +48,7 @@ import java.io.OutputStream;  import java.util.ArrayList;  import java.util.Iterator;  import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean;  public class PgpImportExport { @@ -56,6 +59,7 @@ public class PgpImportExport {      private Context mContext;      private Progressable mProgressable; +    private AtomicBoolean mCancelled;      private KeychainServiceListener mKeychainServiceListener; @@ -72,6 +76,14 @@ public class PgpImportExport {          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,                             Progressable progressable, KeychainServiceListener keychainListener) {          super(); @@ -143,6 +155,11 @@ public class PgpImportExport {          int position = 0;          double progSteps = 100.0 / num;          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 {                  UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes()); @@ -208,9 +225,13 @@ public class PgpImportExport {                  }              }              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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 967a7caa9..6b1433cca 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 021e6bc07..2073d6a6c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -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; @@ -72,6 +75,7 @@ import java.io.IOException;  import java.io.OutputStream;  import java.util.ArrayList;  import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean;  /**   * 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_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"; @@ -110,6 +114,8 @@ public class KeychainIntentService extends IntentService      public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE"; +    public static final String ACTION_CANCEL = Constants.INTENT_PREFIX + "CANCEL"; +      /* keys for data bundle */      // encrypt, decrypt, import export @@ -141,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"; @@ -196,6 +202,8 @@ public class KeychainIntentService extends IntentService      Messenger mMessenger;      private boolean mIsCanceled; +    // this attribute can possibly merged with the one above? not sure... +    private AtomicBoolean mActionCanceled = new AtomicBoolean(false);      public KeychainIntentService() {          super("KeychainIntentService"); @@ -214,6 +222,10 @@ public class KeychainIntentService extends IntentService       */      @Override      protected void onHandleIntent(Intent intent) { + +        // We have not been cancelled! (yet) +        mActionCanceled.set(false); +          Bundle extras = intent.getExtras();          if (extras == null) {              Log.e(Constants.TAG, "Extras bundle is null!"); @@ -400,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); @@ -436,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)); @@ -499,12 +526,17 @@ public class KeychainIntentService extends IntentService                  }                  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); +                // we do this even on failure or cancellation!                  if (result.mSecret > 0) { +                    // cannot cancel from here on out! +                    sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_PREVENT_CANCEL);                      providerHelper.consolidateDatabaseStep1(this);                  } +                  // make sure new data is synced into contacts                  ContactSyncAdapterService.requestSync(); @@ -612,7 +644,6 @@ public class KeychainIntentService extends IntentService                  ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size());                  for (ImportKeysListEntry entry : entries) { -                      Keyserver server;                      if (entry.getOrigin() == null) {                          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 {          int target = data.getInt(TARGET);          switch (target) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index 0cdbe708e..940777458 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -18,7 +18,6 @@  package org.sufficientlysecure.keychain.service;  import android.app.Activity; -import android.content.DialogInterface.OnCancelListener;  import android.os.Bundle;  import android.os.Handler;  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_EXCEPTION = 2;      public static final int MESSAGE_UPDATE_PROGRESS = 3; +    public static final int MESSAGE_PREVENT_CANCEL = 4;      // possible data keys for messages      public static final String DATA_ERROR = "error"; @@ -60,18 +60,16 @@ public class KeychainIntentServiceHandler extends Handler {      public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,                                          int progressDialogStyle) { -        this(activity, progressDialogMessage, progressDialogStyle, false, null); +        this(activity, progressDialogMessage, progressDialogStyle, false);      }      public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, -                                        int progressDialogStyle, boolean cancelable, -                                        OnCancelListener onCancelListener) { +                                        int progressDialogStyle, boolean cancelable) {          this.mActivity = activity;          this.mProgressDialogFragment = ProgressDialogFragment.newInstance(                  progressDialogMessage,                  progressDialogStyle, -                cancelable, -                onCancelListener); +                cancelable);      }      public void showProgressDialog(FragmentActivity activity) { @@ -126,6 +124,9 @@ public class KeychainIntentServiceHandler extends Handler {                  break; +            case MESSAGE_PREVENT_CANCEL: +                mProgressDialogFragment.setPreventCancel(true); +              default:                  Log.e(Constants.TAG, "unknown handler message!");                  break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index fe699224b..4e89d0243 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -55,13 +55,17 @@ public class OperationResultParcel implements Parcelable {      public static final String EXTRA_RESULT = "operation_result"; -    /** Holds the overall result, the number specifying varying degrees of success. The first bit -     * is 0 on overall success, 1 on overall failure. All other bits may be used for more specific -     * conditions. */ +    /** Holds the overall result, the number specifying varying degrees of success: +     *  - The first bit is 0 on overall success, 1 on overall failure +     *  - 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;      public static final int RESULT_OK = 0;      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.      final OperationLog mLog; @@ -82,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() { @@ -147,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(); @@ -223,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), @@ -440,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 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java index f3d0b9e9b..822c069cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java @@ -26,6 +26,7 @@ import android.view.View;  import com.github.johnpersano.supertoasts.SuperCardToast;  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.Style; @@ -44,16 +45,14 @@ public abstract class OperationResults {          public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;          // 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 -        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) -        public static final int RESULT_WITH_ERRORS = 8; -        // There are warnings in the log -        public static final int RESULT_WITH_WARNINGS = 16; +        public static final int RESULT_WITH_ERRORS = 32;          // 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() {              return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED)) @@ -119,15 +118,20 @@ public abstract class OperationResults {              if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {                  String withWarnings; +                duration = Duration.EXTRA_LONG; +                color = Style.GREEN; +                withWarnings = ""; +                  // Any warnings? -                if ((resultType & ImportKeyResult.RESULT_WITH_WARNINGS) > 0) { +                if ((resultType & ImportKeyResult.RESULT_WARNINGS) > 0) {                      duration = 0;                      color = Style.ORANGE; -                    withWarnings = activity.getResources().getString(R.string.import_with_warnings); -                } else { -                    duration = SuperToast.Duration.LONG; -                    color = Style.GREEN; -                    withWarnings = ""; +                    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 @@ -152,13 +156,14 @@ public abstract class OperationResults {                  duration = 0;                  color = Style.RED;                  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 {                      str = activity.getString(R.string.import_error);                  }              } -            // TODO: externalize into Notify class?              boolean button = getLog() != null && !getLog().isEmpty();              SuperCardToast toast = new SuperCardToast(activity,                      button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, @@ -243,7 +248,7 @@ public abstract class OperationResults {          }          // Some old key was updated -        public static final int UPDATED = 2; +        public static final int UPDATED = 4;          // Public key was saved          public static final int SAVED_PUBLIC = 8; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 69f4af04b..ec4f2e337 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -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; @@ -45,7 +44,6 @@ import org.sufficientlysecure.keychain.service.OperationResults;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;  import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Notify;  public class CreateKeyFinalFragment extends Fragment { @@ -126,7 +124,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 +176,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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 28692f638..2137af65f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -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); +      }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 96fa11363..7ad7d1007 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui;  import android.annotation.TargetApi;  import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener;  import android.content.Intent;  import android.net.Uri;  import android.nfc.NdefMessage; @@ -447,7 +449,8 @@ public class ImportKeysActivity extends ActionBarActivity {          KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(                  this,                  getString(R.string.progress_importing), -                ProgressDialog.STYLE_HORIZONTAL) { +                ProgressDialog.STYLE_HORIZONTAL, +                true) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java index e524c3870..1202de1b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java @@ -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; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java index 0324dd3b9..d09be2d51 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java @@ -21,32 +21,29 @@ import android.app.Activity;  import android.app.Dialog;  import android.app.ProgressDialog;  import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener;  import android.content.DialogInterface.OnKeyListener; +import android.content.Intent; +import android.graphics.Color;  import android.os.Bundle;  import android.support.v4.app.DialogFragment;  import android.view.ContextThemeWrapper;  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.service.KeychainIntentService;  public class ProgressDialogFragment extends DialogFragment {      private static final String ARG_MESSAGE = "message";      private static final String ARG_STYLE = "style";      private static final String ARG_CANCELABLE = "cancelable"; -    private OnCancelListener mOnCancelListener; +    boolean mCanCancel = false, mPreventCancel = false, mIsCancelled = false; -    /** -     * Creates new instance of this fragment -     * -     * @param message -     * @param style -     * @param cancelable -     * @return -     */ -    public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable, -                                                     OnCancelListener onCancelListener) { +    /** Creates new instance of this fragment */ +    public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable) {          ProgressDialogFragment frag = new ProgressDialogFragment();          Bundle args = new Bundle();          args.putString(ARG_MESSAGE, message); @@ -54,43 +51,33 @@ public class ProgressDialogFragment extends DialogFragment {          args.putBoolean(ARG_CANCELABLE, cancelable);          frag.setArguments(args); -        frag.mOnCancelListener = onCancelListener;          return frag;      } -    /** -     * Updates progress of dialog -     * -     * @param messageId -     * @param progress -     * @param max -     */ +    /** Updates progress of dialog */      public void setProgress(int messageId, int progress, int max) {          setProgress(getString(messageId), progress, max);      } -    /** -     * Updates progress of dialog -     * -     * @param progress -     * @param max -     */ +    /** Updates progress of dialog */      public void setProgress(int progress, int max) { +        if (mIsCancelled) { +            return; +        } +          ProgressDialog dialog = (ProgressDialog) getDialog();          dialog.setProgress(progress);          dialog.setMax(max);      } -    /** -     * Updates progress of dialog -     * -     * @param message -     * @param progress -     * @param max -     */ +    /** Updates progress of dialog */      public void setProgress(String message, int progress, int max) { +        if (mIsCancelled) { +            return; +        } +          ProgressDialog dialog = (ProgressDialog) getDialog();          dialog.setMessage(message); @@ -98,15 +85,6 @@ public class ProgressDialogFragment extends DialogFragment {          dialog.setMax(max);      } -    @Override -    public void onCancel(DialogInterface dialog) { -        super.onCancel(dialog); - -        if (this.mOnCancelListener != null) { -            this.mOnCancelListener.onCancel(dialog); -        } -    } -      /**       * Creates dialog       */ @@ -121,41 +99,88 @@ public class ProgressDialogFragment extends DialogFragment {          ProgressDialog dialog = new ProgressDialog(context);          dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); +        // We never use the builtin cancel method          dialog.setCancelable(false);          dialog.setCanceledOnTouchOutside(false);          String message = getArguments().getString(ARG_MESSAGE);          int style = getArguments().getInt(ARG_STYLE); -        boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE); +        mCanCancel = getArguments().getBoolean(ARG_CANCELABLE);          dialog.setMessage(message);          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, -                    activity.getString(R.string.progress_cancel), -                    new DialogInterface.OnClickListener() { -                        @Override -                        public void onClick(DialogInterface dialog, int which) { -                            dialog.cancel(); -                        } -                    }); +                    activity.getString(R.string.progress_cancel), (DialogInterface.OnClickListener) null);          } -        // Disable the back button +        // Disable the back button regardless          OnKeyListener keyListener = new OnKeyListener() { -              @Override              public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {                  if (keyCode == KeyEvent.KEYCODE_BACK) { +                    if (mCanCancel) { +                        ((ProgressDialog) dialog).getButton( +                                DialogInterface.BUTTON_NEGATIVE).performClick(); +                    } +                    // return true, indicating we handled this                      return true;                  }                  return false;              } -          };          dialog.setOnKeyListener(keyListener);          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); +            } +        }); + +    } +  } diff --git a/OpenKeychain/src/main/res/layout/decrypt_activity.xml b/OpenKeychain/src/main/res/layout/decrypt_activity.xml index 94d82fe1d..bb0e463b3 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_activity.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_activity.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <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:layout_width="match_parent"      android:layout_height="match_parent"> @@ -9,4 +8,4 @@      <include layout="@layout/drawer_list" /> -</android.support.v4.widget.FixedDrawerLayout>
\ No newline at end of file +</android.support.v4.widget.FixedDrawerLayout> diff --git a/OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml b/OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml index 4ac60620d..3b4eba3ef 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <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_height="match_parent"      android:fillViewport="true"> diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml index 6c5e12266..19b3c38e4 100644 --- a/OpenKeychain/src/main/res/values-de/strings.xml +++ b/OpenKeychain/src/main/res/values-de/strings.xml @@ -443,7 +443,7 @@    <!--Consolidate-->    <!--PassphraseCache-->    <!--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_cert">Zertifikatdetails</string>    <string name="label_user_id">Identität</string> diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml index bd72a4fed..1bd73f389 100644 --- a/OpenKeychain/src/main/res/values-es/strings.xml +++ b/OpenKeychain/src/main/res/values-es/strings.xml @@ -662,7 +662,7 @@    <string name="passp_cache_notif_clear">Limpiar caché</string>    <string name="passp_cache_notif_pwd">Contraseña</string>    <!--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_cert">Detalles del certificado</string>    <string name="label_user_id">Identidad</string> diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml index 3aa0f1f5d..1b0a355d3 100644 --- a/OpenKeychain/src/main/res/values-fr/strings.xml +++ b/OpenKeychain/src/main/res/values-fr/strings.xml @@ -662,7 +662,7 @@    <string name="passp_cache_notif_clear">Effacer le cache</string>    <string name="passp_cache_notif_pwd">Mot de passe</string>    <!--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_cert">Détails du certificat</string>    <string name="label_user_id">identité</string> diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml index b8707ab70..d117b44d8 100644 --- a/OpenKeychain/src/main/res/values-it/strings.xml +++ b/OpenKeychain/src/main/res/values-it/strings.xml @@ -662,7 +662,7 @@    <string name="passp_cache_notif_clear">Pulisci Cache</string>    <string name="passp_cache_notif_pwd">Password</string>    <!--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_cert">Dettagli Certificato</string>    <string name="label_user_id">Identit</string> diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml index 41426cb9b..5859a85ff 100644 --- a/OpenKeychain/src/main/res/values-ja/strings.xml +++ b/OpenKeychain/src/main/res/values-ja/strings.xml @@ -637,7 +637,7 @@    <string name="passp_cache_notif_clear">キャッシュクリア</string>    <string name="passp_cache_notif_pwd">パスワード</string>    <!--unsorted--> -  <string name="internal_error">内部エラー!</string> +  <string name="msg_internal_error">内部エラー!</string>    <string name="section_certifier_id">検証者</string>    <string name="section_cert">証明の詳細</string>    <string name="label_user_id">ユーザID</string> diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml index b94749ee5..48c180103 100644 --- a/OpenKeychain/src/main/res/values-uk/strings.xml +++ b/OpenKeychain/src/main/res/values-uk/strings.xml @@ -601,7 +601,7 @@    <string name="passp_cache_notif_clear">Очистити кеш</string>    <string name="passp_cache_notif_pwd">Пароль</string>    <!--unsorted--> -  <string name="internal_error">Внутрішня помилка!</string> +  <string name="msg_internal_error">Внутрішня помилка!</string>    <string name="section_certifier_id">Ким підписаний</string>    <string name="section_cert">Дані сертифікату</string>    <string name="label_user_id">Сутність</string> diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 16970b4dd..2a2d18c0d 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -262,6 +262,7 @@      <!-- progress dialogs, usually ending in '…' -->      <string name="progress_done">Done.</string>      <string name="progress_cancel">Cancel</string> +    <string name="progress_cancelling">cancelling…</string>      <string name="progress_saving">saving…</string>      <string name="progress_importing">importing…</string>      <string name="progress_exporting">exporting…</string> @@ -381,8 +382,10 @@      </plurals>      <string name="view_log">View Log</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_with_warnings">, with warnings</string> +    <string name="import_with_cancelled">, until cancelled</string>      <!-- Intent labels -->      <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 ! --> +    <string name="msg_internal_error">Internal error!</string> +    <string name="msg_cancelled">Operation cancelled.</string> +      <!-- Import Public log entries -->      <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> @@ -744,7 +750,6 @@      <string name="passp_cache_notif_pwd">Password</string>      <!-- unsorted --> -    <string name="internal_error">Internal error!</string>      <string name="section_certifier_id">Certifier</string>      <string name="section_cert">Certificate Details</string>      <string name="label_user_id">Identity</string>  | 
