aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java333
1 files changed, 211 insertions, 122 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
index 6eb5b9d2d..b7fffc7ff 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
@@ -17,6 +17,12 @@
package org.sufficientlysecure.keychain.ui;
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Vector;
+
+import org.spongycastle.bcpg.sig.KeyFlags;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
@@ -41,7 +47,6 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
@@ -51,19 +56,27 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
+import org.sufficientlysecure.keychain.ui.widget.Editor;
import org.sufficientlysecure.keychain.ui.widget.KeyEditor;
import org.sufficientlysecure.keychain.ui.widget.SectionView;
import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
+import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
-import java.util.ArrayList;
-import java.util.GregorianCalendar;
-import java.util.Vector;
-public class EditKeyActivity extends ActionBarActivity {
+import android.app.AlertDialog;
+import android.support.v4.app.ActivityCompat;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class EditKeyActivity extends ActionBarActivity implements EditorListener {
// Actions for internal use only:
public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY";
@@ -90,6 +103,9 @@ public class EditKeyActivity extends ActionBarActivity {
private String mNewPassPhrase = null;
private String mSavedNewPassPhrase = null;
private boolean mIsPassPhraseSet;
+ private boolean mNeedsSaving;
+ private boolean mIsBrandNewKeyring = false;
+ private MenuItem mSaveButton;
private BootstrapButton mChangePassphrase;
@@ -102,12 +118,42 @@ public class EditKeyActivity extends ActionBarActivity {
ExportHelper mExportHelper;
+ public boolean needsSaving()
+ {
+ mNeedsSaving = (mUserIdsView == null) ? false : mUserIdsView.needsSaving();
+ mNeedsSaving |= (mKeysView == null) ? false : mKeysView.needsSaving();
+ mNeedsSaving |= hasPassphraseChanged();
+ mNeedsSaving |= mIsBrandNewKeyring;
+ return mNeedsSaving;
+ }
+
+
+ public void somethingChanged()
+ {
+ ActivityCompat.invalidateOptionsMenu(this);
+ //Toast.makeText(this, "Needs saving: " + Boolean.toString(mNeedsSaving) + "(" + Boolean.toString(mUserIdsView.needsSaving()) + ", " + Boolean.toString(mKeysView.needsSaving()) + ")", Toast.LENGTH_LONG).show();
+ }
+
+ public void onDeleted(Editor e, boolean wasNewItem)
+ {
+ somethingChanged();
+ }
+
+ public void onEdited()
+ {
+ somethingChanged();
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mExportHelper = new ExportHelper(this);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setIcon(android.R.color.transparent);
+ getSupportActionBar().setHomeButtonEnabled(true);
+
mUserIds = new Vector<String>();
mKeys = new Vector<PGPSecretKey>();
mKeysUsages = new Vector<Integer>();
@@ -128,24 +174,10 @@ public class EditKeyActivity extends ActionBarActivity {
* @param intent
*/
private void handleActionCreateKey(Intent intent) {
- // Inflate a "Save"/"Cancel" custom action bar
- ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- saveClicked();
- }
- }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- cancelClicked();
- }
- }
- );
-
Bundle extras = intent.getExtras();
mCurrentPassphrase = "";
+ mIsBrandNewKeyring = true;
if (extras != null) {
// if userId is given, prefill the fields
@@ -203,22 +235,24 @@ public class EditKeyActivity extends ActionBarActivity {
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
// get new key from data bundle returned from service
Bundle data = message.getData();
- PGPSecretKey masterKey = (PGPSecretKey) PgpConversionHelper
+ PGPSecretKey masterKey = PgpConversionHelper
.BytesToPGPSecretKey(data
.getByteArray(KeychainIntentService.RESULT_NEW_KEY));
- PGPSecretKey subKey = (PGPSecretKey) PgpConversionHelper
+ PGPSecretKey subKey = PgpConversionHelper
.BytesToPGPSecretKey(data
.getByteArray(KeychainIntentService.RESULT_NEW_KEY2));
+ //We must set the key flags here as they are not set when we make the
+ //key pair. Because we are not generating hashed packets there...
// add master key
mKeys.add(masterKey);
- mKeysUsages.add(Id.choice.usage.sign_only); //TODO: get from key flags
+ mKeysUsages.add(KeyFlags.CERTIFY_OTHER);
// add sub key
mKeys.add(subKey);
- mKeysUsages.add(Id.choice.usage.encrypt_only); //TODO: get from key flags
+ mKeysUsages.add(KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE);
- buildLayout();
+ buildLayout(true);
}
}
};
@@ -234,7 +268,7 @@ public class EditKeyActivity extends ActionBarActivity {
}
}
} else {
- buildLayout();
+ buildLayout(false);
}
}
@@ -244,40 +278,29 @@ public class EditKeyActivity extends ActionBarActivity {
* @param intent
*/
private void handleActionEditKey(Intent intent) {
- // Inflate a "Save"/"Cancel" custom action bar
- ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- saveClicked();
- }
- });
-
mDataUri = intent.getData();
if (mDataUri == null) {
Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!");
finish();
- return;
} else {
Log.d(Constants.TAG, "uri: " + mDataUri);
// get master key id using row id
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
- mMasterCanSign = ProviderHelper.getMasterKeyCanSign(this, mDataUri);
- finallyEdit(masterKeyId, mMasterCanSign);
+ mMasterCanSign = ProviderHelper.getMasterKeyCanCertify(this, mDataUri);
+ finallyEdit(masterKeyId);
}
}
- private void showPassphraseDialog(final long masterKeyId, final boolean masterCanSign) {
+ private void showPassphraseDialog(final long masterKeyId) {
// Message is received after passphrase is cached
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
- String passphrase = PassphraseCacheService.getCachedPassphrase(
+ mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(
EditKeyActivity.this, masterKeyId);
- mCurrentPassphrase = passphrase;
finallySaveClicked();
}
}
@@ -299,59 +322,65 @@ public class EditKeyActivity extends ActionBarActivity {
}
@Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- // show menu only on edit
- if (mDataUri != null) {
- return super.onPrepareOptionsMenu(menu);
- } else {
- return false;
- }
- }
-
- @Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.key_edit, menu);
+ mSaveButton = menu.findItem(R.id.menu_key_edit_save);
+ mSaveButton.setEnabled(needsSaving());
+ //totally get rid of some actions for new keys
+ if (mDataUri == null) {
+ MenuItem mButton = menu.findItem(R.id.menu_key_edit_export_file);
+ mButton.setVisible(false);
+ mButton = menu.findItem(R.id.menu_key_edit_delete);
+ mButton.setVisible(false);
+ }
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case R.id.menu_key_edit_cancel:
- cancelClicked();
- return true;
- case R.id.menu_key_edit_export_file:
+ case android.R.id.home:
+ cancelClicked(); //TODO: why isn't this triggered on my tablet - one of many ui problems I've had with this device. A code compatibility issue or a Samsung fail?
+ return true;
+ case R.id.menu_key_edit_cancel:
+ cancelClicked();
+ return true;
+ case R.id.menu_key_edit_export_file:
+ if (needsSaving()) {
+ Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
+ } else {
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
long[] ids = new long[]{masterKeyId};
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC,
null);
return true;
- case R.id.menu_key_edit_delete: {
- //Convert the uri to one based on rowId
- long rowId= ProviderHelper.getRowId(this,mDataUri);
- Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(Long.toString(rowId));
-
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
- setResult(RESULT_CANCELED);
- finish();
- }
+ }
+ return true;
+ case R.id.menu_key_edit_delete:
+ long rowId= ProviderHelper.getRowId(this,mDataUri);
+ Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(Long.toString(rowId));
+ // Message is received after key is deleted
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
+ setResult(RESULT_CANCELED);
+ finish();
}
- };
+ }};
+ mExportHelper.deleteKey(convertUri, returnHandler);
+ return true;
- mExportHelper.deleteKey(convertUri, returnHandler);
- return true;
- }
+ case R.id.menu_key_edit_save:
+ saveClicked();
+ return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("unchecked")
- private void finallyEdit(final long masterKeyId, final boolean masterCanSign) {
+ private void finallyEdit(final long masterKeyId) {
if (masterKeyId != 0) {
PGPSecretKey masterKey = null;
mKeyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(this, masterKeyId);
@@ -366,16 +395,24 @@ public class EditKeyActivity extends ActionBarActivity {
Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_LONG).show();
}
if (masterKey != null) {
+ boolean isSet = false;
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
Log.d(Constants.TAG, "Added userId " + userId);
+ if (!isSet) {
+ isSet = true;
+ String[] parts = PgpKeyHelper.splitUserId(userId);
+ if (parts[0] != null)
+ setTitle(parts[0]);
+ }
mUserIds.add(userId);
}
}
}
mCurrentPassphrase = "";
+ buildLayout(false);
+
mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
- buildLayout();
if (!mIsPassPhraseSet) {
// check "no passphrase" checkbox and remove button
mNoPassphrase.setChecked(true);
@@ -399,6 +436,7 @@ public class EditKeyActivity extends ActionBarActivity {
.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
updatePassPhraseButtonText();
+ somethingChanged();
}
}
};
@@ -407,7 +445,7 @@ public class EditKeyActivity extends ActionBarActivity {
Messenger messenger = new Messenger(returnHandler);
// set title based on isPassphraseSet()
- int title = -1;
+ int title;
if (isPassphraseSet()) {
title = R.string.title_change_passphrase;
} else {
@@ -423,8 +461,9 @@ public class EditKeyActivity extends ActionBarActivity {
/**
* Build layout based on mUserId, mKeys and mKeysUsages Vectors. It creates Views for every user
* id and key.
+ * @param newKeys
*/
- private void buildLayout() {
+ private void buildLayout(boolean newKeys) {
setContentView(R.layout.edit_key_activity);
// find views
@@ -442,11 +481,13 @@ public class EditKeyActivity extends ActionBarActivity {
mUserIdsView.setType(Id.type.user_id);
mUserIdsView.setCanEdit(mMasterCanSign);
mUserIdsView.setUserIds(mUserIds);
+ mUserIdsView.setEditorListener(this);
container.addView(mUserIdsView);
mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
mKeysView.setType(Id.type.key);
mKeysView.setCanEdit(mMasterCanSign);
- mKeysView.setKeys(mKeys, mKeysUsages);
+ mKeysView.setKeys(mKeys, mKeysUsages, newKeys);
+ mKeysView.setEditorListener(this);
container.addView(mKeysView);
updatePassPhraseButtonText();
@@ -457,7 +498,7 @@ public class EditKeyActivity extends ActionBarActivity {
}
});
- // disable passphrase when no passphrase checkobox is checked!
+ // disable passphrase when no passphrase checkbox is checked!
mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
@@ -471,6 +512,7 @@ public class EditKeyActivity extends ActionBarActivity {
mNewPassPhrase = mSavedNewPassPhrase;
mChangePassphrase.setVisibility(View.VISIBLE);
}
+ somethingChanged();
}
});
}
@@ -493,27 +535,54 @@ public class EditKeyActivity extends ActionBarActivity {
}
}
- private void saveClicked() {
- long masterKeyId = getMasterKeyId();
- if (!isPassphraseSet()) {
- Log.e(Constants.TAG, "No passphrase has been set");
- Toast.makeText(this, R.string.set_a_passphrase, Toast.LENGTH_LONG).show();
- } else {
- String passphrase = null;
- if (mIsPassPhraseSet) {
- passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
+ public boolean hasPassphraseChanged()
+ {
+ if (mNoPassphrase != null) {
+ if (mNoPassphrase.isChecked()) {
+ return mIsPassPhraseSet;
} else {
- passphrase = "";
+ return (mNewPassPhrase != null && !mNewPassPhrase.equals(""));
}
- if (passphrase == null) {
- showPassphraseDialog(masterKeyId, mMasterCanSign);
- } else {
- mCurrentPassphrase = passphrase;
- finallySaveClicked();
+ }else {
+ return false;
+ }
+ }
+
+ private void saveClicked() {
+ long masterKeyId = getMasterKeyId();
+ if (needsSaving()) { //make sure, as some versions don't support invalidateOptionsMenu
+ try {
+ if (!isPassphraseSet()) {
+ throw new PgpGeneralException(this.getString(R.string.set_a_passphrase));
+ }
+
+ String passphrase;
+ if (mIsPassPhraseSet)
+ passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
+ else
+ passphrase = "";
+ if (passphrase == null) {
+ showPassphraseDialog(masterKeyId);
+ } else {
+ mCurrentPassphrase = passphrase;
+ finallySaveClicked();
+ }
+ } catch (PgpGeneralException e) {
+ Toast.makeText(this, getString(R.string.error_message, e.getMessage()),
+ Toast.LENGTH_SHORT).show();
}
}
}
+ private boolean[] toPrimitiveArray(final List<Boolean> booleanList) {
+ final boolean[] primitives = new boolean[booleanList.size()];
+ int index = 0;
+ for (Boolean object : booleanList) {
+ primitives[index++] = object;
+ }
+ return primitives;
+ }
+
private void finallySaveClicked() {
try {
// Send all information needed to service to edit key in other thread
@@ -521,22 +590,26 @@ public class EditKeyActivity extends ActionBarActivity {
intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
+ SaveKeyringParcel saveParams = new SaveKeyringParcel();
+ saveParams.userIDs = getUserIds(mUserIdsView);
+ saveParams.originalIDs = mUserIdsView.getOriginalIDs();
+ saveParams.deletedIDs = mUserIdsView.getDeletedIDs();
+ saveParams.primaryIDChanged = mUserIdsView.primaryChanged();
+ saveParams.moddedKeys = toPrimitiveArray(mKeysView.getNeedsSavingArray());
+ saveParams.deletedKeys = mKeysView.getDeletedKeys();
+ saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
+ saveParams.keysUsages = getKeysUsages(mKeysView);
+ saveParams.newPassPhrase = mNewPassPhrase;
+ saveParams.oldPassPhrase = mCurrentPassphrase;
+ saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
+ saveParams.keys = getKeys(mKeysView);
+ saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID();
+
+
// fill values for this action
Bundle data = new Bundle();
- data.putString(KeychainIntentService.SAVE_KEYRING_CURRENT_PASSPHRASE,
- mCurrentPassphrase);
- data.putString(KeychainIntentService.SAVE_KEYRING_NEW_PASSPHRASE, mNewPassPhrase);
- data.putStringArrayList(KeychainIntentService.SAVE_KEYRING_USER_IDS,
- getUserIds(mUserIdsView));
- ArrayList<PGPSecretKey> keys = getKeys(mKeysView);
- data.putByteArray(KeychainIntentService.SAVE_KEYRING_KEYS,
- PgpConversionHelper.PGPSecretKeyArrayListToBytes(keys));
- data.putIntegerArrayList(KeychainIntentService.SAVE_KEYRING_KEYS_USAGES,
- getKeysUsages(mKeysView));
- data.putSerializable(KeychainIntentService.SAVE_KEYRING_KEYS_EXPIRY_DATES,
- getKeysExpiryDates(mKeysView));
- data.putLong(KeychainIntentService.SAVE_KEYRING_MASTER_KEY_ID, getMasterKeyId());
data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign);
+ data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@@ -579,8 +652,35 @@ public class EditKeyActivity extends ActionBarActivity {
}
private void cancelClicked() {
- setResult(RESULT_CANCELED);
- finish();
+ if (needsSaving()) { //ask if we want to save
+ AlertDialog.Builder alert = new AlertDialog.Builder(
+ EditKeyActivity.this);
+
+ alert.setIcon(android.R.drawable.ic_dialog_alert);
+ alert.setTitle(R.string.warning);
+ alert.setMessage(EditKeyActivity.this.getString(R.string.ask_save_changed_key));
+
+ alert.setPositiveButton(EditKeyActivity.this.getString(android.R.string.yes),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ saveClicked();
+ }
+ });
+ alert.setNegativeButton(this.getString(android.R.string.no),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ alert.setCancelable(false);
+ alert.create().show();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
}
/**
@@ -597,19 +697,8 @@ public class EditKeyActivity extends ActionBarActivity {
boolean gotMainUserId = false;
for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
- String userId = null;
- try {
- userId = editor.getValue();
- } catch (UserIdEditor.NoNameException e) {
- throw new PgpGeneralException(this.getString(R.string.error_user_id_needs_a_name));
- } catch (UserIdEditor.NoEmailException e) {
- throw new PgpGeneralException(
- this.getString(R.string.error_user_id_needs_an_email_address));
- }
-
- if (userId.equals("")) {
- continue;
- }
+ String userId;
+ userId = editor.getValue();
if (editor.isMainUserId()) {
userIds.add(0, userId);
@@ -698,4 +787,4 @@ public class EditKeyActivity extends ActionBarActivity {
: getString(R.string.btn_set_passphrase));
}
-} \ No newline at end of file
+}