diff options
8 files changed, 133 insertions, 51 deletions
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 067af3f7c..0bc3ac0ab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -135,10 +135,10 @@ public class PgpImportExport {          // If there aren't even any keys, do nothing here.          if (entries == null || !entries.hasNext()) {              return new ImportKeyResult( -                    ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0); +                    ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0, 0);          } -        int newKeys = 0, oldKeys = 0, badKeys = 0; +        int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0;          int position = 0;          double progSteps = 100.0 / num; @@ -173,6 +173,9 @@ public class PgpImportExport {                      oldKeys += 1;                  } else {                      newKeys += 1; +                    if (key.isSecret()) { +                        secret += 1; +                    }                  }              } catch (IOException e) { @@ -209,7 +212,7 @@ public class PgpImportExport {              }          } -        return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys); +        return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret);      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 8fd4bc7cf..6447a180c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -832,6 +832,8 @@ public class ProviderHelper {          log(LogLevel.START, LogType.MSG_CON);          mIndent += 1; +        progress.setProgress(R.string.progress_con_saving, 0, 100); +          try {              log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET); @@ -891,6 +893,8 @@ public class ProviderHelper {              mIndent -= 1;          } +        progress.setProgress(R.string.progress_con_saving, 3, 100); +          // 1b. fetch all public keyrings into a cache file          try { @@ -998,11 +1002,6 @@ public class ProviderHelper {              log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR);              mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); -            // debug: break if this isn't recovery -            if (!recovery) { -                return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); -            } -              FileImportCache<ParcelableKeyRing> cacheSecret =                      new FileImportCache<ParcelableKeyRing>(mContext, "consolidate_secret.pcl");              FileImportCache<ParcelableKeyRing> cachePublic = 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 e82c43d82..ad2932f92 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable;  import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +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; @@ -104,6 +105,8 @@ public class KeychainIntentService extends IntentService      public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING"; +    public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE"; +      public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";      /* keys for data bundle */ @@ -143,6 +146,10 @@ public class KeychainIntentService extends IntentService      // delete file securely      public static final String DELETE_FILE = "deleteFile"; +    // delete keyring(s) +    public static final String DELETE_KEY_LIST = "delete_list"; +    public static final String DELETE_IS_SECRET = "delete_is_secret"; +      // import key      public static final String IMPORT_KEY_LIST = "import_key_list";      public static final String IMPORT_KEY_FILE = "import_key_file"; @@ -487,9 +494,14 @@ public class KeychainIntentService extends IntentService                      entries = cache.readCacheIntoList();                  } -                PgpImportExport pgpImportExport = new PgpImportExport(this, this); +                ProviderHelper providerHelper = new ProviderHelper(this); +                PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this);                  ImportKeyResult result = pgpImportExport.importKeyRings(entries); +                if (result.mSecret > 0) { +                    providerHelper.consolidateDatabaseStep1(this); +                } +                  sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);              } catch (Exception e) {                  sendErrorToHandler(e); @@ -667,6 +679,42 @@ public class KeychainIntentService extends IntentService                  sendErrorToHandler(e);              } +        } else if (ACTION_DELETE.equals(action)) { + +            try { + +                long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); +                boolean isSecret = data.getBoolean(DELETE_IS_SECRET); + +                if (masterKeyIds.length == 0) { +                    throw new PgpGeneralException("List of keys to delete is empty"); +                } + +                if (isSecret && masterKeyIds.length > 1) { +                    throw new PgpGeneralException("Secret keys can only be deleted individually!"); +                } + +                boolean success = false; +                for (long masterKeyId : masterKeyIds) { +                    int count = getContentResolver().delete( +                            KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null +                    ); +                    success |= count > 0; +                } + +                if (isSecret && success) { +                    ConsolidateResult result = +                            new ProviderHelper(this).consolidateDatabaseStep1(this); +                } + +                if (success) { +                    sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); +                } + +            } catch (Exception e) { +                sendErrorToHandler(e); +            } +          } else if (ACTION_CONSOLIDATE.equals(action)) {              ConsolidateResult result;              if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { 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 878f6ca47..c59a7d172 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java @@ -40,7 +40,7 @@ public abstract class OperationResults {      public static class ImportKeyResult extends OperationResultParcel { -        public final int mNewKeys, mUpdatedKeys, mBadKeys; +        public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;          // At least one new key          public static final int RESULT_OK_NEWKEYS = 2; @@ -76,14 +76,16 @@ public abstract class OperationResults {              mNewKeys = source.readInt();              mUpdatedKeys = source.readInt();              mBadKeys = source.readInt(); +            mSecret = source.readInt();          }          public ImportKeyResult(int result, OperationLog log, -                               int newKeys, int updatedKeys, int badKeys) { +                               int newKeys, int updatedKeys, int badKeys, int secret) {              super(result, log);              mNewKeys = newKeys;              mUpdatedKeys = updatedKeys;              mBadKeys = badKeys; +            mSecret = secret;          }          @Override @@ -92,6 +94,7 @@ public abstract class OperationResults {              dest.writeInt(mNewKeys);              dest.writeInt(mUpdatedKeys);              dest.writeInt(mBadKeys); +            dest.writeInt(mSecret);          }          public static Creator<ImportKeyResult> CREATOR = new Creator<ImportKeyResult>() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index d1109631a..96a332d3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -79,6 +79,9 @@ public class KeyListFragment extends LoaderFragment      private KeyListAdapter mAdapter;      private StickyListHeadersListView mStickyList; +    // saves the mode object for multiselect, needed for reset at some point +    private ActionMode mActionMode = null; +      private String mQuery;      private SearchView mSearchView;      // empty list layout @@ -146,6 +149,7 @@ public class KeyListFragment extends LoaderFragment                  public boolean onCreateActionMode(ActionMode mode, Menu menu) {                      android.view.MenuInflater inflater = getActivity().getMenuInflater();                      inflater.inflate(R.menu.key_list_multi, menu); +                    mActionMode = mode;                      return true;                  } @@ -191,6 +195,7 @@ public class KeyListFragment extends LoaderFragment                  @Override                  public void onDestroyActionMode(ActionMode mode) { +                    mActionMode = null;                      mAdapter.clearSelection();                  } @@ -286,6 +291,13 @@ public class KeyListFragment extends LoaderFragment          // this view is made visible if no data is available          mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty)); +        // end action mode, if any +        if (mActionMode != null) { +            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { +                mActionMode.finish(); +            } +        } +          // The list should now be shown.          if (isResumed()) {              setContentShown(true); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index c9db79740..2c0881ea4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -54,6 +54,8 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;  import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;  import org.sufficientlysecure.keychain.service.OperationResultParcel;  import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;  import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout; @@ -303,8 +305,10 @@ public class ViewKeyActivity extends ActionBarActivity implements          Handler returnHandler = new Handler() {              @Override              public void handleMessage(Message message) { -                setResult(RESULT_CANCELED); -                finish(); +                if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { +                    setResult(RESULT_CANCELED); +                    finish(); +                }              }          }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 4927a4d24..d0c9cea5b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -18,7 +18,9 @@  package org.sufficientlysecure.keychain.ui.dialog;  import android.app.Dialog; +import android.app.ProgressDialog;  import android.content.DialogInterface; +import android.content.Intent;  import android.os.Bundle;  import android.os.Message;  import android.os.Messenger; @@ -31,9 +33,10 @@ import android.widget.TextView;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;  import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;  import org.sufficientlysecure.keychain.util.Log;  import java.util.HashMap; @@ -48,8 +51,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {      private TextView mMainMessage;      private View mInflateView; -    private Messenger mMessenger; -      /**       * Creates new instance of this delete file dialog fragment       */ @@ -68,7 +69,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {      @Override      public Dialog onCreateDialog(Bundle savedInstanceState) {          final FragmentActivity activity = getActivity(); -        mMessenger = getArguments().getParcelable(ARG_MESSENGER); +        final Messenger messenger = getArguments().getParcelable(ARG_MESSENGER);          final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); @@ -83,6 +84,8 @@ public class DeleteKeyDialogFragment extends DialogFragment {          builder.setTitle(R.string.warning); +        final boolean hasSecret; +          // If only a single key has been selected          if (masterKeyIds.length == 1) {              long masterKeyId = masterKeyIds[0]; @@ -98,7 +101,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {                          }                  );                  String userId = (String) data.get(KeyRings.USER_ID); -                boolean hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1; +                hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1;                  // Set message depending on which key it is.                  mMainMessage.setText(getString( @@ -107,12 +110,12 @@ public class DeleteKeyDialogFragment extends DialogFragment {                          userId                  ));              } catch (ProviderHelper.NotFoundException e) { -                sendMessageToHandler(MESSAGE_ERROR, null);                  dismiss();                  return null;              }          } else {              mMainMessage.setText(R.string.key_deletion_confirmation_multi); +            hasSecret = false;          }          builder.setIcon(R.drawable.ic_dialog_alert_holo_light); @@ -120,18 +123,45 @@ public class DeleteKeyDialogFragment extends DialogFragment {              @Override              public void onClick(DialogInterface dialog, int which) { -                boolean success = false; -                for (long masterKeyId : masterKeyIds) { -                    int count = activity.getContentResolver().delete( -                            KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null -                    ); -                    success = count > 0; -                } -                if (success) { -                    sendMessageToHandler(MESSAGE_OKAY, null); -                } else { -                    sendMessageToHandler(MESSAGE_ERROR, null); -                } +                // Send all information needed to service to import key in other thread +                Intent intent = new Intent(getActivity(), KeychainIntentService.class); + +                intent.setAction(KeychainIntentService.ACTION_DELETE); + +                // Message is received after importing is done in KeychainIntentService +                KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +                        getActivity(), +                        getString(R.string.progress_deleting), +                        ProgressDialog.STYLE_HORIZONTAL) { +                    public void handleMessage(Message message) { +                        // handle messages by standard KeychainIntentServiceHandler first +                        super.handleMessage(message); +                        try { +                            Message msg = Message.obtain(); +                            msg.copyFrom(message); +                            messenger.send(msg); +                        } catch (RemoteException e) { +                            Log.e(Constants.TAG, "messenger error", e); +                        } +                    } +                }; + +                // fill values for this action +                Bundle data = new Bundle(); +                data.putLongArray(KeychainIntentService.DELETE_KEY_LIST, masterKeyIds); +                data.putBoolean(KeychainIntentService.DELETE_IS_SECRET, hasSecret); +                intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + +                // Create a new Messenger for the communication back +                Messenger messenger = new Messenger(saveHandler); +                intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + +                // show progress dialog +                saveHandler.showProgressDialog(getActivity()); + +                // start service with intent +                getActivity().startService(intent); +                  dismiss();              }          }); @@ -146,23 +176,4 @@ public class DeleteKeyDialogFragment extends DialogFragment {          return builder.show();      } -    /** -     * Send message back to handler which is initialized in a activity -     * -     * @param what Message integer you want to send -     */ -    private void sendMessageToHandler(Integer what, Bundle data) { -        Message msg = Message.obtain(); -        msg.what = what; -        if (data != null) { -            msg.setData(data); -        } -        try { -            mMessenger.send(msg); -        } catch (RemoteException e) { -            Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); -        } catch (NullPointerException e) { -            Log.w(Constants.TAG, "Messenger is null!", e); -        } -    }  } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 556df3923..2eb9f2b97 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -301,8 +301,10 @@      <string name="progress_decompressing_data">decompressing data…</string>      <string name="progress_verifying_integrity">verifying integrity…</string>      <string name="progress_deleting_securely">deleting \'%s\' securely…</string> +    <string name="progress_deleting">deleting keys…</string> -    <string name="progress_con_reimport">reimporting database…</string> +    <string name="progress_con_saving">consolidate: saving to cache…</string> +    <string name="progress_con_reimport">consolidate: reimporting…</string>      <!-- action strings -->      <string name="hint_keyserver_search_hint">Name/Email/Key ID…</string>  | 
