rewrite EncryptActivity data flow

This commit is contained in:
Vincent Breitmoser 2015-05-27 21:15:36 +02:00
parent 08e0357471
commit 6c17734e73
10 changed files with 355 additions and 486 deletions

View File

@ -77,8 +77,6 @@ public class CertifyKeyFragment extends CryptoOperationFragment
private long[] mPubMasterKeyIds; private long[] mPubMasterKeyIds;
private long mSignMasterKeyId = Constants.key.none;
public static final String[] USER_IDS_PROJECTION = new String[]{ public static final String[] USER_IDS_PROJECTION = new String[]{
UserPackets._ID, UserPackets._ID,
UserPackets.MASTER_KEY_ID, UserPackets.MASTER_KEY_ID,
@ -149,19 +147,13 @@ public class CertifyKeyFragment extends CryptoOperationFragment
vActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), vActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
PorterDuff.Mode.SRC_IN); PorterDuff.Mode.SRC_IN);
mCertifyKeySpinner.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
@Override
public void onKeyChanged(long masterKeyId) {
mSignMasterKeyId = masterKeyId;
}
});
View vCertifyButton = view.findViewById(R.id.certify_key_certify_button); View vCertifyButton = view.findViewById(R.id.certify_key_certify_button);
vCertifyButton.setOnClickListener(new OnClickListener() { vCertifyButton.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (mSignMasterKeyId == Constants.key.none) { long selectedKeyId = mCertifyKeySpinner.getSelectedKeyId();
if (selectedKeyId == Constants.key.none) {
Notify.create(getActivity(), getString(R.string.select_key_to_certify), Notify.create(getActivity(), getString(R.string.select_key_to_certify),
Notify.Style.ERROR).show(); Notify.Style.ERROR).show();
} else { } else {
@ -307,8 +299,10 @@ public class CertifyKeyFragment extends CryptoOperationFragment
Bundle data = new Bundle(); Bundle data = new Bundle();
{ {
long selectedKeyId = mCertifyKeySpinner.getSelectedKeyId();
// fill values for this action // fill values for this action
CertifyActionsParcel parcel = new CertifyActionsParcel(mSignMasterKeyId); CertifyActionsParcel parcel = new CertifyActionsParcel(selectedKeyId);
parcel.mCertifyActions.addAll(certifyActions); parcel.mCertifyActions.addAll(certifyActions);
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
public class EncryptActivity extends BaseActivity {
// preselect ids, for internal use
public static final String EXTRA_SIGNATURE_KEY_ID = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_ID";
public static final String EXTRA_ENCRYPTION_KEY_IDS = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_IDS";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras == null) {
extras = new Bundle();
}
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// preselect keys given by intent
long signingKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID);
long[] encryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
Fragment modeFragment = EncryptModeAsymmetricFragment.newInstance(signingKeyId, encryptionKeyIds);
transaction.replace(R.id.encrypt_mode_container, modeFragment);
transaction.commit();
}
}
public void toggleModeFragment() {
boolean symmetric = getModeFragment() instanceof EncryptModeAsymmetricFragment;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.encrypt_mode_container,
symmetric
? EncryptModeSymmetricFragment.newInstance()
: EncryptModeAsymmetricFragment.newInstance(0, null)
);
// doesn't matter if the user doesn't look at the activity
transaction.commitAllowingStateLoss();
}
public EncryptModeFragment getModeFragment() {
return (EncryptModeFragment)
getSupportFragmentManager().findFragmentById(R.id.encrypt_mode_container);
}
}

View File

@ -18,39 +18,25 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.view.View; import android.view.View;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents; import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
public class EncryptFilesActivity extends BaseActivity implements public class EncryptFilesActivity extends EncryptActivity {
EncryptModeAsymmetricFragment.IAsymmetric, EncryptModeSymmetricFragment.ISymmetric,
EncryptFilesFragment.IMode {
/* Intents */ // Intents
public static final String ACTION_ENCRYPT_DATA = OpenKeychainIntents.ENCRYPT_DATA; public static final String ACTION_ENCRYPT_DATA = OpenKeychainIntents.ENCRYPT_DATA;
// enables ASCII Armor for file encryption when uri is given // enables ASCII Armor for file encryption when uri is given
public static final String EXTRA_ASCII_ARMOR = OpenKeychainIntents.ENCRYPT_EXTRA_ASCII_ARMOR; public static final String EXTRA_ASCII_ARMOR = OpenKeychainIntents.ENCRYPT_EXTRA_ASCII_ARMOR;
// preselect ids, for internal use
public static final String EXTRA_SIGNATURE_KEY_ID = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_ID";
public static final String EXTRA_ENCRYPTION_KEY_IDS = Constants.EXTRA_PREFIX + "EXTRA_ENCRYPTION_IDS";
Fragment mModeFragment;
EncryptFilesFragment mEncryptFragment;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -62,19 +48,7 @@ public class EncryptFilesActivity extends BaseActivity implements
} }
}, false); }, false);
// Handle intent actions Intent intent = getIntent();
handleActions(getIntent(), savedInstanceState);
}
@Override
protected void initLayout() {
setContentView(R.layout.encrypt_files_activity);
}
/**
* Handles all actions with this intent
*/
private void handleActions(Intent intent, Bundle savedInstanceState) {
String action = intent.getAction(); String action = intent.getAction();
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
String type = intent.getType(); String type = intent.getType();
@ -88,10 +62,6 @@ public class EncryptFilesActivity extends BaseActivity implements
uris.add(intent.getData()); uris.add(intent.getData());
} }
/*
* Android's Action
*/
// When sending to OpenKeychain Encrypt via share menu // When sending to OpenKeychain Encrypt via share menu
if (Intent.ACTION_SEND.equals(action) && type != null) { if (Intent.ACTION_SEND.equals(action) && type != null) {
// Files via content provider, override uri and action // Files via content provider, override uri and action
@ -103,56 +73,21 @@ public class EncryptFilesActivity extends BaseActivity implements
uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
} }
long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID);
long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
boolean useArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, false); boolean useArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, false);
if (savedInstanceState == null) { if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
mModeFragment = EncryptModeAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); EncryptFilesFragment encryptFragment = EncryptFilesFragment.newInstance(uris, useArmor);
transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode"); transaction.replace(R.id.encrypt_file_container, encryptFragment);
mEncryptFragment = EncryptFilesFragment.newInstance(uris, useArmor);
transaction.replace(R.id.encrypt_file_container, mEncryptFragment, "files");
transaction.commit(); transaction.commit();
getSupportFragmentManager().executePendingTransactions();
} }
} }
@Override @Override
public void onModeChanged(boolean symmetric) { protected void initLayout() {
// switch fragments setContentView(R.layout.encrypt_files_activity);
getSupportFragmentManager().beginTransaction()
.replace(R.id.encrypt_mode_container,
symmetric
? EncryptModeSymmetricFragment.newInstance()
: EncryptModeAsymmetricFragment.newInstance(0, null)
)
.commitAllowingStateLoss();
getSupportFragmentManager().executePendingTransactions();
}
@Override
public void onSignatureKeyIdChanged(long signatureKeyId) {
mEncryptFragment.setSigningKeyId(signatureKeyId);
}
@Override
public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds) {
mEncryptFragment.setEncryptionKeyIds(encryptionKeyIds);
}
@Override
public void onEncryptionUserIdsChanged(String[] encryptionUserIds) {
mEncryptFragment.setEncryptionUserIds(encryptionUserIds);
}
@Override
public void onPassphraseChanged(Passphrase passphrase) {
mEncryptFragment.setPassphrase(passphrase);
} }
} }

View File

@ -72,19 +72,12 @@ import java.util.Set;
public class EncryptFilesFragment extends CryptoOperationFragment { public class EncryptFilesFragment extends CryptoOperationFragment {
public interface IMode {
public void onModeChanged(boolean symmetric);
}
public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor"; public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor";
public static final String ARG_URIS = "uris"; public static final String ARG_URIS = "uris";
private static final int REQUEST_CODE_INPUT = 0x00007003; private static final int REQUEST_CODE_INPUT = 0x00007003;
private static final int REQUEST_CODE_OUTPUT = 0x00007007; private static final int REQUEST_CODE_OUTPUT = 0x00007007;
private IMode mModeInterface;
private boolean mSymmetricMode = false;
private boolean mUseArmor = false; private boolean mUseArmor = false;
private boolean mUseCompression = true; private boolean mUseCompression = true;
private boolean mDeleteAfterEncrypt = false; private boolean mDeleteAfterEncrypt = false;
@ -92,11 +85,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
private boolean mEncryptFilenames = true; private boolean mEncryptFilenames = true;
private boolean mHiddenRecipients = false; private boolean mHiddenRecipients = false;
private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null;
private long mSigningKeyId = Constants.key.none;
private Passphrase mPassphrase = new Passphrase();
private ArrayList<Uri> mOutputUris = new ArrayList<>(); private ArrayList<Uri> mOutputUris = new ArrayList<>();
private RecyclerView mSelectedFiles; private RecyclerView mSelectedFiles;
@ -118,29 +106,11 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
return frag; return frag;
} }
public void setEncryptionKeyIds(long[] encryptionKeyIds) {
mEncryptionKeyIds = encryptionKeyIds;
}
public void setEncryptionUserIds(String[] encryptionUserIds) {
mEncryptionUserIds = encryptionUserIds;
}
public void setSigningKeyId(long signingKeyId) {
mSigningKeyId = signingKeyId;
}
public void setPassphrase(Passphrase passphrase) {
mPassphrase = passphrase;
}
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
try { if ( ! (activity instanceof EncryptActivity) ) {
mModeInterface = (IMode) activity; throw new AssertionError(activity + " must inherit from EncryptionActivity");
} catch (ClassCastException e) {
throw new ClassCastException(activity + " must be IMode");
} }
} }
@ -293,8 +263,8 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
break; break;
} }
case R.id.check_use_symmetric: { case R.id.check_use_symmetric: {
mSymmetricMode = item.isChecked(); EncryptActivity encryptActivity = (EncryptActivity) getActivity();
mModeInterface.onModeChanged(mSymmetricMode); encryptActivity.toggleModeFragment();
break; break;
} }
case R.id.check_use_armor: { case R.id.check_use_armor: {
@ -325,53 +295,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
return true; return true;
} }
protected boolean inputIsValid() {
// file checks
if (mFilesModels.isEmpty()) {
Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR)
.show(this);
return false;
} else if (mFilesModels.size() > 1 && !mShareAfterEncrypt) {
Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt");
// This should be impossible...
return false;
} else if (mFilesModels.size() != mOutputUris.size()) {
Log.e(Constants.TAG, "Aborting: mInputUris.size() != mOutputUris.size()");
// This as well
return false;
}
if (mSymmetricMode) {
// symmetric encryption checks
if (mPassphrase == null) {
Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR)
.show(this);
return false;
}
if (mPassphrase.isEmpty()) {
Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
.show(this);
return false;
}
} else {
// asymmetric encryption checks
boolean gotEncryptionKeys = (mEncryptionKeyIds != null
&& mEncryptionKeyIds.length > 0);
// Files must be encrypted, only text can be signed-only right now
if (!gotEncryptionKeys) {
Notify.create(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR)
.show(this);
return false;
}
}
return true;
}
public void onEncryptSuccess(final SignEncryptResult result) { public void onEncryptSuccess(final SignEncryptResult result) {
if (mDeleteAfterEncrypt) { if (mDeleteAfterEncrypt) {
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment deleteFileDialog =
@ -403,6 +326,21 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
} }
protected SignEncryptParcel createEncryptBundle() { protected SignEncryptParcel createEncryptBundle() {
if (mFilesModels.isEmpty()) {
Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR)
.show(this);
return null;
} else if (mFilesModels.size() > 1 && !mShareAfterEncrypt) {
Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt");
// This should be impossible...
return null;
} else if (mFilesModels.size() != mOutputUris.size()) {
Log.e(Constants.TAG, "Aborting: mInputUris.size() != mOutputUris.size()");
// This as well
return null;
}
// fill values for this action // fill values for this action
SignEncryptParcel data = new SignEncryptParcel(); SignEncryptParcel data = new SignEncryptParcel();
@ -419,17 +357,39 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
if (mSymmetricMode) { EncryptActivity encryptActivity = (EncryptActivity) getActivity();
Log.d(Constants.TAG, "Symmetric encryption enabled!"); EncryptModeFragment modeFragment = encryptActivity.getModeFragment();
Passphrase passphrase = mPassphrase;
if (modeFragment.isAsymmetric()) {
long[] encryptionKeyIds = modeFragment.getAsymmetricEncryptionKeyIds();
long signingKeyId = modeFragment.getAsymmetricSigningKeyId();
boolean gotEncryptionKeys = (encryptionKeyIds != null
&& encryptionKeyIds.length > 0);
if (!gotEncryptionKeys && signingKeyId == 0) {
Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR)
.show(this);
return null;
}
data.setEncryptionMasterKeyIds(encryptionKeyIds);
data.setSignatureMasterKeyId(signingKeyId);
} else {
Passphrase passphrase = modeFragment.getSymmetricPassphrase();
if (passphrase == null) {
Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR)
.show(this);
return null;
}
if (passphrase.isEmpty()) { if (passphrase.isEmpty()) {
passphrase = null; Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
.show(this);
return null;
} }
data.setSymmetricPassphrase(passphrase); data.setSymmetricPassphrase(passphrase);
} else {
data.setEncryptionMasterKeyIds(mEncryptionKeyIds);
data.setSignatureMasterKeyId(mSigningKeyId);
} }
return data; return data;
} }
@ -461,16 +421,27 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
} }
sendIntent.setType(Constants.ENCRYPTED_FILES_MIME); sendIntent.setType(Constants.ENCRYPTED_FILES_MIME);
if (!mSymmetricMode && mEncryptionUserIds != null) { EncryptActivity modeInterface = (EncryptActivity) getActivity();
EncryptModeFragment modeFragment = modeInterface.getModeFragment();
if (!modeFragment.isAsymmetric()) {
return sendIntent;
}
String[] encryptionUserIds = modeFragment.getAsymmetricEncryptionUserIds();
if (encryptionUserIds == null) {
return sendIntent;
}
Set<String> users = new HashSet<>(); Set<String> users = new HashSet<>();
for (String user : mEncryptionUserIds) { for (String user : encryptionUserIds) {
KeyRing.UserId userId = KeyRing.splitUserId(user); KeyRing.UserId userId = KeyRing.splitUserId(user);
if (userId.email != null) { if (userId.email != null) {
users.add(userId.email); users.add(userId.email);
} }
} }
// pass trough email addresses as extra for email applications
sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
return sendIntent; return sendIntent;
} }
@ -482,19 +453,17 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
@Override @Override
protected void cryptoOperation(CryptoInputParcel cryptoInput) { protected void cryptoOperation(CryptoInputParcel cryptoInput) {
if (!inputIsValid()) { final SignEncryptParcel input = createEncryptBundle();
// this is null if invalid, just return in that case
if (input == null) {
// Notify was created by inputIsValid. // Notify was created by inputIsValid.
Log.d(Constants.TAG, "Input not valid!");
return; return;
} }
Log.d(Constants.TAG, "Input valid!");
// Send all information needed to service to edit key in other thread // Send all information needed to service to edit key in other thread
Intent intent = new Intent(getActivity(), KeychainIntentService.class); Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT);
final SignEncryptParcel input = createEncryptBundle();
Bundle data = new Bundle(); Bundle data = new Bundle();
data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input);
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
@ -727,7 +696,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
for (Uri inputUri : inputUris) { for (Uri inputUri : inputUris) {
ViewModel newModel = new ViewModel(mActivity, inputUri); ViewModel newModel = new ViewModel(mActivity, inputUri);
if (mDataset.contains(newModel)) { if (mDataset.contains(newModel)) {
Log.e(Constants.TAG, "Skipped duplicate " + inputUri.toString()); Log.e(Constants.TAG, "Skipped duplicate " + inputUri);
} else { } else {
mDataset.add(newModel); mDataset.add(newModel);
} }

View File

@ -17,18 +17,13 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
@ -39,38 +34,19 @@ import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView; import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
public class EncryptModeAsymmetricFragment extends Fragment { public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
public interface IAsymmetric {
public void onSignatureKeyIdChanged(long signatureKeyId);
public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds);
public void onEncryptionUserIdsChanged(String[] encryptionUserIds);
}
ProviderHelper mProviderHelper; ProviderHelper mProviderHelper;
// view private KeySpinner mSignKeySpinner;
private KeySpinner mSign;
private EncryptKeyCompletionView mEncryptKeyView; private EncryptKeyCompletionView mEncryptKeyView;
// model
private IAsymmetric mEncryptInterface;
// @Override
// public void updateUi() {
// if (mSign != null) {
// mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey());
// }
// }
public static final String ARG_SINGATURE_KEY_ID = "signature_key_id"; public static final String ARG_SINGATURE_KEY_ID = "signature_key_id";
public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids";
@ -89,16 +65,6 @@ public class EncryptModeAsymmetricFragment extends Fragment {
return frag; return frag;
} }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mEncryptInterface = (IAsymmetric) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity + " must implement IAsymmetric");
}
}
/** /**
* Inflate the layout for this fragment * Inflate the layout for this fragment
*/ */
@ -106,13 +72,7 @@ public class EncryptModeAsymmetricFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
mSign = (KeySpinner) view.findViewById(R.id.sign); mSignKeySpinner = (KeySpinner) view.findViewById(R.id.sign);
mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
@Override
public void onKeyChanged(long masterKeyId) {
mEncryptInterface.onSignatureKeyIdChanged(masterKeyId);
}
});
mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list);
mEncryptKeyView.setThreshold(1); // Start working from first character mEncryptKeyView.setThreshold(1); // Start working from first character
@ -128,22 +88,6 @@ public class EncryptModeAsymmetricFragment extends Fragment {
long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID); long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID);
long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS); long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS);
preselectKeys(signatureKeyId, encryptionKeyIds); preselectKeys(signatureKeyId, encryptionKeyIds);
mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() {
@Override
public void onTokenAdded(Object token) {
if (token instanceof KeyItem) {
updateEncryptionKeys();
}
}
@Override
public void onTokenRemoved(Object token) {
if (token instanceof KeyItem) {
updateEncryptionKeys();
}
}
});
} }
/** /**
@ -155,8 +99,7 @@ public class EncryptModeAsymmetricFragment extends Fragment {
CachedPublicKeyRing keyring = mProviderHelper.getCachedPublicKeyRing( CachedPublicKeyRing keyring = mProviderHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(signatureKeyId)); KeyRings.buildUnifiedKeyRingUri(signatureKeyId));
if (keyring.hasAnySecret()) { if (keyring.hasAnySecret()) {
mEncryptInterface.onSignatureKeyIdChanged(keyring.getMasterKeyId()); mSignKeySpinner.setSelectedKeyId(signatureKeyId);
mSign.setSelectedKeyId(signatureKeyId);
} }
} catch (PgpKeyNotFoundException e) { } catch (PgpKeyNotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);
@ -175,27 +118,55 @@ public class EncryptModeAsymmetricFragment extends Fragment {
} }
// This is to work-around a rendering bug in TokenCompleteTextView // This is to work-around a rendering bug in TokenCompleteTextView
mEncryptKeyView.requestFocus(); mEncryptKeyView.requestFocus();
updateEncryptionKeys();
} }
} }
private void updateEncryptionKeys() { @Override
List<Object> objects = mEncryptKeyView.getObjects(); public boolean isAsymmetric() {
return true;
}
@Override
public long getAsymmetricSigningKeyId() {
return mSignKeySpinner.getSelectedItemId();
}
@Override
public long[] getAsymmetricEncryptionKeyIds() {
List<Long> keyIds = new ArrayList<>(); List<Long> keyIds = new ArrayList<>();
List<String> userIds = new ArrayList<>(); for (Object object : mEncryptKeyView.getObjects()) {
for (Object object : objects) {
if (object instanceof KeyItem) { if (object instanceof KeyItem) {
keyIds.add(((KeyItem) object).mKeyId); keyIds.add(((KeyItem) object).mKeyId);
userIds.add(((KeyItem) object).mUserIdFull);
} }
} }
long[] keyIdsArr = new long[keyIds.size()]; long[] keyIdsArr = new long[keyIds.size()];
Iterator<Long> iterator = keyIds.iterator(); Iterator<Long> iterator = keyIds.iterator();
for (int i = 0; i < keyIds.size(); i++) { for (int i = 0; i < keyIds.size(); i++) {
keyIdsArr[i] = iterator.next(); keyIdsArr[i] = iterator.next();
} }
mEncryptInterface.onEncryptionKeyIdsChanged(keyIdsArr);
mEncryptInterface.onEncryptionUserIdsChanged(userIds.toArray(new String[userIds.size()])); return keyIdsArr;
}
@Override
public String[] getAsymmetricEncryptionUserIds() {
List<String> userIds = new ArrayList<>();
for (Object object : mEncryptKeyView.getObjects()) {
if (object instanceof KeyItem) {
userIds.add(((KeyItem) object).mUserIdFull);
} }
} }
return userIds.toArray(new String[userIds.size()]);
}
@Override
public Passphrase getSymmetricPassphrase() {
throw new UnsupportedOperationException("should never happen, this is a programming error!");
}
}

View File

@ -0,0 +1,19 @@
package org.sufficientlysecure.keychain.ui;
import android.support.v4.app.Fragment;
import org.sufficientlysecure.keychain.util.Passphrase;
public abstract class EncryptModeFragment extends Fragment {
public abstract boolean isAsymmetric();
public abstract long getAsymmetricSigningKeyId();
public abstract long[] getAsymmetricEncryptionKeyIds();
public abstract String[] getAsymmetricEncryptionUserIds();
public abstract Passphrase getSymmetricPassphrase();
}

View File

@ -17,11 +17,7 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -30,14 +26,7 @@ import android.widget.EditText;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
public class EncryptModeSymmetricFragment extends Fragment { public class EncryptModeSymmetricFragment extends EncryptModeFragment {
public interface ISymmetric {
public void onPassphraseChanged(Passphrase passphrase);
}
private ISymmetric mEncryptInterface;
private EditText mPassphrase; private EditText mPassphrase;
private EditText mPassphraseAgain; private EditText mPassphraseAgain;
@ -54,53 +43,54 @@ public class EncryptModeSymmetricFragment extends Fragment {
return frag; return frag;
} }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mEncryptInterface = (ISymmetric) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement ISymmetric");
}
}
/**
* Inflate the layout for this fragment
*/
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_symmetric_fragment, container, false); View view = inflater.inflate(R.layout.encrypt_symmetric_fragment, container, false);
mPassphrase = (EditText) view.findViewById(R.id.passphrase); mPassphrase = (EditText) view.findViewById(R.id.passphrase);
mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain); mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain);
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
// update passphrase in EncryptActivity
Passphrase p1 = new Passphrase(mPassphrase.getText());
Passphrase p2 = new Passphrase(mPassphraseAgain.getText());
boolean passesEquals = (p1.equals(p2));
p1.removeFromMemory();
p2.removeFromMemory();
if (passesEquals) {
mEncryptInterface.onPassphraseChanged(new Passphrase(mPassphrase.getText()));
} else {
mEncryptInterface.onPassphraseChanged(null);
}
}
};
mPassphrase.addTextChangedListener(textWatcher);
mPassphraseAgain.addTextChangedListener(textWatcher);
return view; return view;
} }
@Override
public boolean isAsymmetric() {
return false;
}
@Override
public long getAsymmetricSigningKeyId() {
throw new UnsupportedOperationException("should never happen, this is a programming error!");
}
@Override
public long[] getAsymmetricEncryptionKeyIds() {
throw new UnsupportedOperationException("should never happen, this is a programming error!");
}
@Override
public String[] getAsymmetricEncryptionUserIds() {
throw new UnsupportedOperationException("should never happen, this is a programming error!");
}
@Override
public Passphrase getSymmetricPassphrase() {
Passphrase p1 = null, p2 = null;
try {
p1 = new Passphrase(mPassphrase.getText());
p2 = new Passphrase(mPassphraseAgain.getText());
if (!p1.equals(p2)) {
return null;
}
return new Passphrase(mPassphrase.getText());
} finally {
if (p1 != null) {
p1.removeFromMemory();
}
if (p2 != null) {
p2.removeFromMemory();
}
}
}
} }

View File

@ -20,20 +20,14 @@ package org.sufficientlysecure.keychain.ui;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.view.View; import android.view.View;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents; import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
public class EncryptTextActivity extends BaseActivity implements public class EncryptTextActivity extends EncryptActivity {
EncryptModeAsymmetricFragment.IAsymmetric, EncryptModeSymmetricFragment.ISymmetric,
EncryptTextFragment.IMode {
/* Intents */ /* Intents */
public static final String ACTION_ENCRYPT_TEXT = OpenKeychainIntents.ENCRYPT_TEXT; public static final String ACTION_ENCRYPT_TEXT = OpenKeychainIntents.ENCRYPT_TEXT;
@ -41,13 +35,6 @@ public class EncryptTextActivity extends BaseActivity implements
/* EXTRA keys for input */ /* EXTRA keys for input */
public static final String EXTRA_TEXT = OpenKeychainIntents.ENCRYPT_EXTRA_TEXT; public static final String EXTRA_TEXT = OpenKeychainIntents.ENCRYPT_EXTRA_TEXT;
// preselect ids, for internal use
public static final String EXTRA_SIGNATURE_KEY_ID = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_ID";
public static final String EXTRA_ENCRYPTION_KEY_IDS = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_IDS";
Fragment mModeFragment;
EncryptTextFragment mEncryptFragment;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -89,23 +76,14 @@ public class EncryptTextActivity extends BaseActivity implements
textData = ""; textData = "";
} }
// preselect keys given by intent
long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID);
long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
if (savedInstanceState == null) { if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
mModeFragment = EncryptModeAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); EncryptTextFragment encryptFragment = EncryptTextFragment.newInstance(textData);
transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode"); transaction.replace(R.id.encrypt_text_container, encryptFragment);
mEncryptFragment = EncryptTextFragment.newInstance(textData);
transaction.replace(R.id.encrypt_text_container, mEncryptFragment, "text");
transaction.commit(); transaction.commit();
getSupportFragmentManager().executePendingTransactions();
} }
} }
@Override @Override
@ -113,44 +91,4 @@ public class EncryptTextActivity extends BaseActivity implements
setContentView(R.layout.encrypt_text_activity); setContentView(R.layout.encrypt_text_activity);
} }
@Override
public void onModeChanged(boolean symmetric) {
// switch fragments
getSupportFragmentManager().beginTransaction()
.replace(R.id.encrypt_mode_container,
symmetric
? EncryptModeSymmetricFragment.newInstance()
: EncryptModeAsymmetricFragment.newInstance(0, null)
)
.commitAllowingStateLoss();
getSupportFragmentManager().executePendingTransactions();
}
@Override
public void onSignatureKeyIdChanged(long signatureKeyId) {
if (mEncryptFragment != null) {
mEncryptFragment.setSigningKeyId(signatureKeyId);
}
}
@Override
public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds) {
if (mEncryptFragment != null) {
mEncryptFragment.setEncryptionKeyIds(encryptionKeyIds);
}
}
@Override
public void onEncryptionUserIdsChanged(String[] encryptionUserIds) {
if (mEncryptFragment != null) {
mEncryptFragment.setEncryptionUserIds(encryptionUserIds);
}
}
@Override
public void onPassphraseChanged(Passphrase passphrase) {
if (mEncryptFragment != null) {
mEncryptFragment.setSymmetricPassphrase(passphrase);
}
}
} }

View File

@ -47,7 +47,6 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ShareHelper; import org.sufficientlysecure.keychain.util.ShareHelper;
@ -56,44 +55,14 @@ import java.util.Set;
public class EncryptTextFragment extends CryptoOperationFragment { public class EncryptTextFragment extends CryptoOperationFragment {
public interface IMode {
public void onModeChanged(boolean symmetric);
}
public static final String ARG_TEXT = "text"; public static final String ARG_TEXT = "text";
private IMode mModeInterface;
private boolean mSymmetricMode = false;
private boolean mShareAfterEncrypt = false; private boolean mShareAfterEncrypt = false;
private boolean mUseCompression = true; private boolean mUseCompression = true;
private boolean mHiddenRecipients = false; private boolean mHiddenRecipients = false;
private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null;
// TODO Constants.key.none? What's wrong with a null value?
private long mSigningKeyId = Constants.key.none;
private Passphrase mSymmetricPassphrase = new Passphrase();
private String mMessage = ""; private String mMessage = "";
private TextView mText;
public void setEncryptionKeyIds(long[] encryptionKeyIds) {
mEncryptionKeyIds = encryptionKeyIds;
}
public void setEncryptionUserIds(String[] encryptionUserIds) {
mEncryptionUserIds = encryptionUserIds;
}
public void setSigningKeyId(long signingKeyId) {
mSigningKeyId = signingKeyId;
}
public void setSymmetricPassphrase(Passphrase passphrase) {
mSymmetricPassphrase = passphrase;
}
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
*/ */
@ -110,10 +79,8 @@ public class EncryptTextFragment extends CryptoOperationFragment {
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
try { if ( ! (activity instanceof EncryptActivity) ) {
mModeInterface = (IMode) activity; throw new AssertionError(activity + " must inherit from EncryptionActivity");
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement IMode");
} }
} }
@ -124,8 +91,8 @@ public class EncryptTextFragment extends CryptoOperationFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_text_fragment, container, false); View view = inflater.inflate(R.layout.encrypt_text_fragment, container, false);
mText = (TextView) view.findViewById(R.id.encrypt_text_text); TextView textView = (TextView) view.findViewById(R.id.encrypt_text_text);
mText.addTextChangedListener(new TextWatcher() { textView.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@ -144,7 +111,7 @@ public class EncryptTextFragment extends CryptoOperationFragment {
// set initial text // set initial text
if (mMessage != null) { if (mMessage != null) {
mText.setText(mMessage); textView.setText(mMessage);
} }
return view; return view;
@ -171,8 +138,8 @@ public class EncryptTextFragment extends CryptoOperationFragment {
} }
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.check_use_symmetric: { case R.id.check_use_symmetric: {
mSymmetricMode = item.isChecked(); EncryptActivity modeInterface = (EncryptActivity) getActivity();
mModeInterface.onModeChanged(mSymmetricMode); modeInterface.toggleModeFragment();
break; break;
} }
case R.id.check_enable_compression: { case R.id.check_enable_compression: {
@ -185,11 +152,11 @@ public class EncryptTextFragment extends CryptoOperationFragment {
// break; // break;
// } // }
case R.id.encrypt_copy: { case R.id.encrypt_copy: {
startEncrypt(false); cryptoOperation(false);
break; break;
} }
case R.id.encrypt_share: { case R.id.encrypt_share: {
startEncrypt(true); cryptoOperation(true);
break; break;
} }
default: { default: {
@ -199,7 +166,6 @@ public class EncryptTextFragment extends CryptoOperationFragment {
return true; return true;
} }
protected void onEncryptSuccess(SignEncryptResult result) { protected void onEncryptSuccess(SignEncryptResult result) {
if (mShareAfterEncrypt) { if (mShareAfterEncrypt) {
// Share encrypted message/file // Share encrypted message/file
@ -215,6 +181,13 @@ public class EncryptTextFragment extends CryptoOperationFragment {
} }
protected SignEncryptParcel createEncryptBundle() { protected SignEncryptParcel createEncryptBundle() {
if (mMessage == null || mMessage.isEmpty()) {
Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR)
.show(this);
return null;
}
// fill values for this action // fill values for this action
SignEncryptParcel data = new SignEncryptParcel(); SignEncryptParcel data = new SignEncryptParcel();
@ -227,22 +200,45 @@ public class EncryptTextFragment extends CryptoOperationFragment {
data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED);
} }
data.setHiddenRecipients(mHiddenRecipients); data.setHiddenRecipients(mHiddenRecipients);
data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); data.setSymmetricEncryptionAlgorithm(
data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
data.setSignatureHashAlgorithm(
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
// Always use armor for messages // Always use armor for messages
data.setEnableAsciiArmorOutput(true); data.setEnableAsciiArmorOutput(true);
if (mSymmetricMode) { EncryptActivity modeInterface = (EncryptActivity) getActivity();
Log.d(Constants.TAG, "Symmetric encryption enabled!"); EncryptModeFragment modeFragment = modeInterface.getModeFragment();
Passphrase passphrase = mSymmetricPassphrase;
if (modeFragment.isAsymmetric()) {
long[] encryptionKeyIds = modeFragment.getAsymmetricEncryptionKeyIds();
long signingKeyId = modeFragment.getAsymmetricSigningKeyId();
boolean gotEncryptionKeys = (encryptionKeyIds != null
&& encryptionKeyIds.length > 0);
if (!gotEncryptionKeys && signingKeyId == 0L) {
Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR)
.show(this);
return null;
}
data.setEncryptionMasterKeyIds(encryptionKeyIds);
data.setSignatureMasterKeyId(signingKeyId);
} else {
Passphrase passphrase = modeFragment.getSymmetricPassphrase();
if (passphrase == null) {
Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR)
.show(this);
return null;
}
if (passphrase.isEmpty()) { if (passphrase.isEmpty()) {
passphrase = null; Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
.show(this);
return null;
} }
data.setSymmetricPassphrase(passphrase); data.setSymmetricPassphrase(passphrase);
} else {
data.setEncryptionMasterKeyIds(mEncryptionKeyIds);
data.setSignatureMasterKeyId(mSigningKeyId);
} }
return data; return data;
} }
@ -273,9 +269,19 @@ public class EncryptTextFragment extends CryptoOperationFragment {
sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME); sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME);
sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes)); sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes));
if (!mSymmetricMode && mEncryptionUserIds != null) { EncryptActivity modeInterface = (EncryptActivity) getActivity();
EncryptModeFragment modeFragment = modeInterface.getModeFragment();
if (!modeFragment.isAsymmetric()) {
return sendIntent;
}
String[] encryptionUserIds = modeFragment.getAsymmetricEncryptionUserIds();
if (encryptionUserIds == null) {
return sendIntent;
}
Set<String> users = new HashSet<>(); Set<String> users = new HashSet<>();
for (String user : mEncryptionUserIds) { for (String user : encryptionUserIds) {
KeyRing.UserId userId = KeyRing.splitUserId(user); KeyRing.UserId userId = KeyRing.splitUserId(user);
if (userId.email != null) { if (userId.email != null) {
users.add(userId.email); users.add(userId.email);
@ -283,55 +289,21 @@ public class EncryptTextFragment extends CryptoOperationFragment {
} }
// pass trough email addresses as extra for email applications // pass trough email addresses as extra for email applications
sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
return sendIntent; return sendIntent;
} }
protected boolean inputIsValid() { public void cryptoOperation(boolean share) {
if (mMessage == null || mMessage.isEmpty()) {
Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR)
.show(this);
return false;
}
if (mSymmetricMode) {
// symmetric encryption checks
if (mSymmetricPassphrase == null) {
Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR)
.show(this);
return false;
}
if (mSymmetricPassphrase.isEmpty()) {
Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
.show(this);
return false;
}
} else {
// asymmetric encryption checks
boolean gotEncryptionKeys = (mEncryptionKeyIds != null
&& mEncryptionKeyIds.length > 0);
if (!gotEncryptionKeys && mSigningKeyId == 0) {
Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR)
.show(this);
return false;
}
}
return true;
}
public void startEncrypt(boolean share) {
mShareAfterEncrypt = share; mShareAfterEncrypt = share;
cryptoOperation(); cryptoOperation();
} }
@Override @Override
protected void cryptoOperation(CryptoInputParcel cryptoInput) { protected void cryptoOperation(CryptoInputParcel cryptoInput) {
if (!inputIsValid()) {
final SignEncryptParcel input = createEncryptBundle();
// this is null if invalid, just return in that case
if (input == null) {
// Notify was created by inputIsValid. // Notify was created by inputIsValid.
return; return;
} }
@ -340,7 +312,6 @@ public class EncryptTextFragment extends CryptoOperationFragment {
Intent intent = new Intent(getActivity(), KeychainIntentService.class); Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT);
final SignEncryptParcel input = createEncryptBundle();
final Bundle data = new Bundle(); final Bundle data = new Bundle();
data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input);
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);

View File

@ -20,12 +20,14 @@ package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Color; import android.graphics.Color;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.CursorAdapter;
import android.support.v7.widget.AppCompatSpinner; import android.support.v7.widget.AppCompatSpinner;
import android.text.format.DateFormat;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
@ -42,17 +44,18 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/** /**
* Use AppCompatSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon. * Use AppCompatSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon.
* Related: http://stackoverflow.com/a/27713090 * Related: http://stackoverflow.com/a/27713090
*/ */
public abstract class KeySpinner extends AppCompatSpinner implements LoaderManager.LoaderCallbacks<Cursor> { public abstract class KeySpinner extends AppCompatSpinner implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_SUPER_STATE = "super_state";
public static final String ARG_SELECTED_KEY_ID = "select_key_id";
public interface OnKeyChangedListener { public interface OnKeyChangedListener {
public void onKeyChanged(long masterKeyId); void onKeyChanged(long masterKeyId);
} }
protected long mSelectedKeyId = Constants.key.none; protected long mSelectedKeyId = Constants.key.none;
@ -82,15 +85,17 @@ public abstract class KeySpinner extends AppCompatSpinner implements LoaderManag
super.setOnItemSelectedListener(new OnItemSelectedListener() { super.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mSelectedKeyId = id;
if (mListener != null) { if (mListener != null) {
mListener.onKeyChanged(id); mListener.onKeyChanged(mSelectedKeyId);
} }
} }
@Override @Override
public void onNothingSelected(AdapterView<?> parent) { public void onNothingSelected(AdapterView<?> parent) {
mSelectedKeyId = Constants.key.none;
if (mListener != null) { if (mListener != null) {
mListener.onKeyChanged(Constants.key.none); mListener.onKeyChanged(mSelectedKeyId);
} }
} }
}); });
@ -138,7 +143,7 @@ public abstract class KeySpinner extends AppCompatSpinner implements LoaderManag
} }
public void setSelectedKeyId(long selectedKeyId) { public void setSelectedKeyId(long selectedKeyId) {
this.mSelectedKeyId = selectedKeyId; mSelectedKeyId = selectedKeyId;
} }
protected class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter { protected class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter {