Load of rework on EncryptActivity, still some TODOs

This commit is contained in:
mar-v-in 2014-07-20 17:09:34 +02:00
parent bc9922263c
commit 2913a78b18
11 changed files with 610 additions and 591 deletions

View File

@ -236,14 +236,19 @@ public class ContactHelper {
} }
public static Bitmap photoFromFingerprint(ContentResolver contentResolver, String fingerprint) { public static Bitmap photoFromFingerprint(ContentResolver contentResolver, String fingerprint) {
int rawContactId = findRawContactId(contentResolver, fingerprint); if (fingerprint == null) return null;
if (rawContactId == -1) return null; try {
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId); int rawContactId = findRawContactId(contentResolver, fingerprint);
Uri contactUri = ContactsContract.RawContacts.getContactLookupUri(contentResolver, rawContactUri); if (rawContactId == -1) return null;
InputStream photoInputStream = Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri); Uri contactUri = ContactsContract.RawContacts.getContactLookupUri(contentResolver, rawContactUri);
if (photoInputStream == null) return null; InputStream photoInputStream =
return BitmapFactory.decodeStream(photoInputStream); ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri);
if (photoInputStream == null) return null;
return BitmapFactory.decodeStream(photoInputStream);
} catch (Throwable ignored) {
return null;
}
} }
/** /**

View File

@ -18,28 +18,38 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.ProgressDialog;
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.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.view.PagerTabStrip; import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.ViewGroup; import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Choice;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class EncryptActivity extends DrawerActivity implements public class EncryptActivity extends DrawerActivity implements EncryptActivityInterface {
EncryptSymmetricFragment.OnSymmetricKeySelection,
EncryptAsymmetricFragment.OnAsymmetricKeySelection,
EncryptActivityInterface {
/* Intents */ /* Intents */
public static final String ACTION_ENCRYPT = Constants.INTENT_PREFIX + "ENCRYPT"; public static final String ACTION_ENCRYPT = Constants.INTENT_PREFIX + "ENCRYPT";
@ -79,40 +89,25 @@ public class EncryptActivity extends DrawerActivity implements
private long mEncryptionKeyIds[] = null; private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null; private String mEncryptionUserIds[] = null;
private long mSigningKeyId = Constants.key.none; private long mSigningKeyId = Constants.key.none;
private String mPassphrase; private String mPassphrase = "";
private String mPassphraseAgain;
private int mCurrentMode = PAGER_MODE_ASYMMETRIC;
private boolean mUseArmor; private boolean mUseArmor;
private boolean mDeleteAfterEncrypt = false; private boolean mDeleteAfterEncrypt = false;
private boolean mShareAfterEncrypt = false;
private ArrayList<Uri> mInputUris;
private ArrayList<Uri> mOutputUris;
private String mMessage;
@Override
public void onSigningKeySelected(long signingKeyId) {
mSigningKeyId = signingKeyId;
}
@Override
public void onEncryptionKeysSelected(long[] encryptionKeyIds) {
mEncryptionKeyIds = encryptionKeyIds;
}
@Override
public void onEncryptionUserSelected(String[] encryptionUserIds) {
mEncryptionUserIds = encryptionUserIds;
}
@Override
public void onPassphraseUpdate(String passphrase) {
mPassphrase = passphrase;
}
@Override
public void onPassphraseAgainUpdate(String passphrase) {
mPassphraseAgain = passphrase;
}
@Override
public boolean isModeSymmetric() { public boolean isModeSymmetric() {
return PAGER_MODE_SYMMETRIC == mCurrentMode; return PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem();
}
public boolean isContentMessage() {
return PAGER_CONTENT_MESSAGE == mViewPagerContent.getCurrentItem();
}
@Override
public boolean isUseArmor() {
return mUseArmor;
} }
@Override @Override
@ -131,23 +126,263 @@ public class EncryptActivity extends DrawerActivity implements
} }
@Override @Override
public String getPassphrase() { public void setSignatureKey(long signatureKey) {
return mPassphrase; mSigningKeyId = signatureKey;
notifyUpdate();
} }
@Override @Override
public String getPassphraseAgain() { public void setEncryptionKeys(long[] encryptionKeys) {
return mPassphraseAgain; mEncryptionKeyIds = encryptionKeys;
notifyUpdate();
} }
@Override @Override
public boolean isUseArmor() { public void setEncryptionUsers(String[] encryptionUsers) {
return mUseArmor; mEncryptionUserIds = encryptionUsers;
notifyUpdate();
} }
@Override @Override
public boolean isDeleteAfterEncrypt() { public void setPassphrase(String passphrase) {
return mDeleteAfterEncrypt; mPassphrase = passphrase;
}
@Override
public ArrayList<Uri> getInputUris() {
if (mInputUris == null) mInputUris = new ArrayList<Uri>();
return mInputUris;
}
@Override
public ArrayList<Uri> getOutputUris() {
if (mOutputUris == null) mOutputUris = new ArrayList<Uri>();
return mOutputUris;
}
@Override
public void setInputUris(ArrayList<Uri> uris) {
mInputUris = uris;
notifyUpdate();
}
@Override
public void setOutputUris(ArrayList<Uri> uris) {
mOutputUris = uris;
notifyUpdate();
}
@Override
public String getMessage() {
return mMessage;
}
@Override
public void setMessage(String message) {
mMessage = message;
}
@Override
public void notifyUpdate() {
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
if (fragment instanceof EncryptActivityInterface.UpdateListener) {
((UpdateListener) fragment).onNotifyUpdate();
}
}
}
@Override
public void startEncrypt(boolean share) {
mShareAfterEncrypt = share;
startEncrypt();
}
public void startEncrypt() {
if (!inputIsValid()) {
// AppMsg was created by inputIsValid.
return;
}
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(this, KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
intent.putExtra(KeychainIntentService.EXTRA_DATA, createEncryptBundle());
// Message is received after encrypting is done in KeychainIntentService
KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler(this,
getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
AppMsg.makeText(EncryptActivity.this, R.string.encrypt_sign_successful, AppMsg.STYLE_INFO).show();
if (!isContentMessage() && mDeleteAfterEncrypt) {
// TODO: Create and show dialog to delete original file
//DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
//deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
//setInputUri(null);
}
if (mShareAfterEncrypt) {
// Share encrypted file
startActivity(Intent.createChooser(createSendIntent(message), getString(R.string.title_share_file)));
} else if (isContentMessage()) {
// Copy to clipboard
copyToClipboard(message);
AppMsg.makeText(EncryptActivity.this,
R.string.encrypt_sign_clipboard_successful, AppMsg.STYLE_INFO).show();
}
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(serviceHandler);
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
// show progress dialog
serviceHandler.showProgressDialog(this);
// start service with intent
startService(intent);
}
private Bundle createEncryptBundle() {
// fill values for this action
Bundle data = new Bundle();
if (isContentMessage()) {
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, mMessage.getBytes());
} else {
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URIS);
data.putParcelableArrayList(KeychainIntentService.ENCRYPT_INPUT_URIS, mInputUris);
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URIS);
data.putParcelableArrayList(KeychainIntentService.ENCRYPT_OUTPUT_URIS, mOutputUris);
}
// Always use armor for messages
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, mUseArmor || isContentMessage());
// TODO: Only default compression right now...
int compressionId = Preferences.getPreferences(this).getDefaultMessageCompression();
data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId);
if (isModeSymmetric()) {
Log.d(Constants.TAG, "Symmetric encryption enabled!");
String passphrase = mPassphrase;
if (passphrase.length() == 0) {
passphrase = null;
}
data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase);
} else {
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID, mSigningKeyId);
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, mEncryptionKeyIds);
}
return data;
}
private void copyToClipboard(Message message) {
ClipboardReflection.copyToClipboard(this, new String(message.getData().getByteArray(KeychainIntentService.RESULT_BYTES)));
}
private Intent createSendIntent(Message message) {
Intent sendIntent;
if (isContentMessage()) {
sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, new String(message.getData().getByteArray(KeychainIntentService.RESULT_BYTES)));
} else {
// file
if (mOutputUris.size() == 1) {
sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("*/*");
sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris.get(0));
} else {
sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
sendIntent.setType("*/*");
sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris);
}
}
if (!isModeSymmetric() && mEncryptionUserIds != null) {
Set<String> users = new HashSet<String>();
for (String user : mEncryptionUserIds) {
String[] userId = KeyRing.splitUserId(user);
if (userId[1] != null) {
users.add(userId[1]);
}
}
sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
return sendIntent;
}
private boolean inputIsValid() {
if (!isContentMessage()) {
// file checks
if (mInputUris.isEmpty()) {
AppMsg.makeText(this, R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
return false;
} else if (mInputUris.size() > 1 && !mShareAfterEncrypt) {
AppMsg.makeText(this, "TODO", AppMsg.STYLE_ALERT).show(); // TODO
return false;
}
if (mInputUris.size() != mOutputUris.size()) {
throw new IllegalStateException("Something went terribly wrong if this happens!");
}
}
if (isModeSymmetric()) {
// symmetric encryption checks
if (mPassphrase == null) {
AppMsg.makeText(this, R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
return false;
}
if (mPassphrase.isEmpty()) {
AppMsg.makeText(this, R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT).show();
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 && !isContentMessage()) {
AppMsg.makeText(this, R.string.select_encryption_key, AppMsg.STYLE_ALERT).show();
return false;
}
if (!gotEncryptionKeys && mSigningKeyId == 0) {
AppMsg.makeText(this, R.string.select_encryption_or_signature_key,
AppMsg.STYLE_ALERT).show();
return false;
}
if (mSigningKeyId != 0 && PassphraseCacheService.getCachedPassphrase(this, mSigningKeyId) == null) {
PassphraseDialogFragment.show(this, mSigningKeyId,
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
// restart
startEncrypt();
}
}
});
return false;
}
}
return true;
} }
private void initView() { private void initView() {
@ -211,12 +446,15 @@ public class EncryptActivity extends DrawerActivity implements
case R.id.check_use_symmetric: case R.id.check_use_symmetric:
mSwitchToMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC; mSwitchToMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC;
mViewPagerMode.setCurrentItem(mSwitchToMode); mViewPagerMode.setCurrentItem(mSwitchToMode);
notifyUpdate();
break; break;
case R.id.check_use_armor: case R.id.check_use_armor:
mUseArmor = item.isChecked(); mUseArmor = item.isChecked();
notifyUpdate();
break; break;
case R.id.check_delete_after_encrypt: case R.id.check_delete_after_encrypt:
mDeleteAfterEncrypt = item.isChecked(); mDeleteAfterEncrypt = item.isChecked();
notifyUpdate();
break; break;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);

View File

@ -17,17 +17,41 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.net.Uri;
import java.util.ArrayList;
public interface EncryptActivityInterface { public interface EncryptActivityInterface {
public boolean isModeSymmetric(); public interface UpdateListener {
void onNotifyUpdate();
}
public boolean isUseArmor();
public long getSignatureKey(); public long getSignatureKey();
public long[] getEncryptionKeys(); public long[] getEncryptionKeys();
public String[] getEncryptionUsers(); public String[] getEncryptionUsers();
public void setSignatureKey(long signatureKey);
public void setEncryptionKeys(long[] encryptionKeys);
public void setEncryptionUsers(String[] encryptionUsers);
public String getPassphrase(); public void setPassphrase(String passphrase);
public String getPassphraseAgain();
boolean isUseArmor(); // ArrayList on purpose as only those are parcelable
boolean isDeleteAfterEncrypt(); public ArrayList<Uri> getInputUris();
public ArrayList<Uri> getOutputUris();
public void setInputUris(ArrayList<Uri> uris);
public void setOutputUris(ArrayList<Uri> uris);
public String getMessage();
public void setMessage(String message);
/**
* Call this to notify the UI for changes done on the array lists or arrays,
* automatically called if setter is used
*/
public void notifyUpdate();
public void startEncrypt(boolean share);
} }

View File

@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -26,14 +26,15 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader; import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
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 android.widget.*; import android.widget.*;
import com.tokenautocomplete.TokenCompleteTextView; 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.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
@ -42,9 +43,13 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView; import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.*; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class EncryptAsymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
private static final String SIGN_KEY_SELECTION = KeyRings.CAN_SIGN + " = 1 AND " + KeyRings.IS_REVOKED + " = 0";
public class EncryptAsymmetricFragment extends Fragment {
public static final String ARG_SIGNATURE_KEY_ID = "signature_key_id"; public static final String ARG_SIGNATURE_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";
@ -53,55 +58,39 @@ public class EncryptAsymmetricFragment extends Fragment {
ProviderHelper mProviderHelper; ProviderHelper mProviderHelper;
OnAsymmetricKeySelection mKeySelectionListener;
// view // view
private CheckBox mSign; private Spinner mSign;
private EncryptKeyCompletionView mEncryptKeyView; private EncryptKeyCompletionView mEncryptKeyView;
private SelectSignKeyCursorAdapter mSignAdapter = new SelectSignKeyCursorAdapter();
// model // model
private long mSecretKeyId = Constants.key.none; private EncryptActivityInterface mEncryptInterface;
private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null;
// Container Activity must implement this interface @Override
public interface OnAsymmetricKeySelection { public void onNotifyUpdate() {
public void onSigningKeySelected(long signingKeyId);
public void onEncryptionKeysSelected(long[] encryptionKeyIds);
public void onEncryptionUserSelected(String[] encryptionUserIds);
} }
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
try { try {
mKeySelectionListener = (OnAsymmetricKeySelection) activity; mEncryptInterface = (EncryptActivityInterface) activity;
} catch (ClassCastException e) { } catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnAsymmetricKeySelection"); throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface");
} }
} }
private void setSignatureKeyId(long signatureKeyId) { private void setSignatureKeyId(long signatureKeyId) {
mSecretKeyId = signatureKeyId; mEncryptInterface.setSignatureKey(signatureKeyId);
// update key selection in EncryptActivity
mKeySelectionListener.onSigningKeySelected(signatureKeyId);
updateView();
} }
private void setEncryptionKeyIds(long[] encryptionKeyIds) { private void setEncryptionKeyIds(long[] encryptionKeyIds) {
mEncryptionKeyIds = encryptionKeyIds; mEncryptInterface.setEncryptionKeys(encryptionKeyIds);
// update key selection in EncryptActivity
mKeySelectionListener.onEncryptionKeysSelected(encryptionKeyIds);
updateView();
} }
private void setEncryptionUserIds(String[] encryptionUserIds) { private void setEncryptionUserIds(String[] encryptionUserIds) {
mEncryptionUserIds = encryptionUserIds; mEncryptInterface.setEncryptionUsers(encryptionUserIds);
// update key selection in EncryptActivity
mKeySelectionListener.onEncryptionUserSelected(encryptionUserIds);
updateView();
} }
/** /**
@ -111,15 +100,17 @@ public class EncryptAsymmetricFragment 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 = (CheckBox) view.findViewById(R.id.sign); mSign = (Spinner) view.findViewById(R.id.sign);
mSign.setOnClickListener(new View.OnClickListener() { mSign.setAdapter(mSignAdapter);
public void onClick(View v) { mSign.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
CheckBox checkBox = (CheckBox) v; @Override
if (checkBox.isChecked()) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectSecretKey(); setSignatureKeyId(parent.getAdapter().getItemId(position));
} else { }
setSignatureKeyId(Constants.key.none);
} @Override
public void onNothingSelected(AdapterView<?> parent) {
setSignatureKeyId(Constants.key.none);
} }
}); });
mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list);
@ -136,6 +127,11 @@ public class EncryptAsymmetricFragment extends Fragment {
mProviderHelper = new ProviderHelper(getActivity()); mProviderHelper = new ProviderHelper(getActivity());
// preselect keys given by arguments (given by Intent to EncryptActivity)
preselectKeys(signatureKeyId, encryptionKeyIds, mProviderHelper);
// TODO: Move this into widget!
getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() { getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
@Override @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@ -146,12 +142,55 @@ public class EncryptAsymmetricFragment extends Fragment {
@Override @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mEncryptKeyView.fromCursor(data); mEncryptKeyView.swapCursor(data);
} }
@Override @Override
public void onLoaderReset(Loader<Cursor> loader) { public void onLoaderReset(Loader<Cursor> loader) {
mEncryptKeyView.fromCursor(null); mEncryptKeyView.swapCursor(null);
}
});
getLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
// These are the rows that we will retrieve.
String[] projection = new String[]{
KeyRings._ID,
KeyRings.MASTER_KEY_ID,
KeyRings.KEY_ID,
KeyRings.USER_ID,
KeyRings.EXPIRY,
KeyRings.IS_REVOKED,
// can certify info only related to master key
KeyRings.CAN_CERTIFY,
// has sign may be any subkey
KeyRings.HAS_SIGN,
KeyRings.HAS_ANY_SECRET,
KeyRings.HAS_SECRET
};
String where = KeyRings.HAS_ANY_SECRET + " = 1";
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
return new CursorLoader(getActivity(), baseUri, projection, where, null, null);
/*return new CursorLoader(getActivity(), KeyRings.buildUnifiedKeyRingsUri(),
new String[]{KeyRings.USER_ID, KeyRings.KEY_ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET}, SIGN_KEY_SELECTION,
null, null);*/
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mSignAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mSignAdapter.swapCursor(null);
} }
}); });
mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() { mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() {
@ -169,9 +208,6 @@ public class EncryptAsymmetricFragment extends Fragment {
} }
} }
}); });
// preselect keys given by arguments (given by Intent to EncryptActivity)
preselectKeys(signatureKeyId, encryptionKeyIds, mProviderHelper);
} }
/** /**
@ -211,42 +247,6 @@ public class EncryptAsymmetricFragment extends Fragment {
} }
} }
private void updateView() {
/*if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) {
mSelectKeysButton.setText(getString(R.string.select_keys_button_default));
} else {
mSelectKeysButton.setText(getResources().getQuantityString(
R.plurals.select_keys_button, mEncryptionKeyIds.length,
mEncryptionKeyIds.length));
}*/
/*
if (mSecretKeyId == Constants.key.none) {
mSign.setChecked(false);
} else {
// See if we can get a user_id from a unified query
String[] userId;
try {
userId = mProviderHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(mSecretKeyId)).getSplitPrimaryUserId();
} catch (PgpGeneralException e) {
userId = null;
}
if (userId != null && userId[0] != null) {
mMainUserId.setText(userId[0]);
} else {
mMainUserId.setText(getResources().getString(R.string.user_id_no_name));
}
if (userId != null && userId[1] != null) {
mMainUserIdRest.setText(userId[1]);
} else {
mMainUserIdRest.setText("");
}
mSign.setChecked(true);
}
*/
}
private void updateEncryptionKeys() { private void updateEncryptionKeys() {
List<Object> objects = mEncryptKeyView.getObjects(); List<Object> objects = mEncryptKeyView.getObjects();
List<Long> keyIds = new ArrayList<Long>(); List<Long> keyIds = new ArrayList<Long>();
@ -266,58 +266,81 @@ public class EncryptAsymmetricFragment extends Fragment {
setEncryptionUserIds(userIds.toArray(new String[userIds.size()])); setEncryptionUserIds(userIds.toArray(new String[userIds.size()]));
} }
private void selectPublicKeys() { private class SelectSignKeyCursorAdapter extends BaseAdapter implements SpinnerAdapter {
Intent intent = new Intent(getActivity(), SelectPublicKeyActivity.class); private CursorAdapter inner;
Vector<Long> keyIds = new Vector<Long>(); private int mIndexUserId;
if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) { private int mIndexKeyId;
for (int i = 0; i < mEncryptionKeyIds.length; ++i) { private int mIndexMasterKeyId;
keyIds.add(mEncryptionKeyIds[i]);
}
}
long[] initialKeyIds = null;
if (keyIds.size() > 0) {
initialKeyIds = new long[keyIds.size()];
for (int i = 0; i < keyIds.size(); ++i) {
initialKeyIds[i] = keyIds.get(i);
}
}
intent.putExtra(SelectPublicKeyActivity.EXTRA_SELECTED_MASTER_KEY_IDS, initialKeyIds);
startActivityForResult(intent, REQUEST_CODE_PUBLIC_KEYS);
}
private void selectSecretKey() { public SelectSignKeyCursorAdapter() {
Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class); inner = new CursorAdapter(null, null, 0) {
intent.putExtra(SelectSecretKeyActivity.EXTRA_FILTER_SIGN, true); @Override
startActivityForResult(intent, REQUEST_CODE_SECRET_KEYS); public View newView(Context context, Cursor cursor, ViewGroup parent) {
} return getActivity().getLayoutInflater().inflate(R.layout.encrypt_asymmetric_signkey, null);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_PUBLIC_KEYS: {
if (resultCode == Activity.RESULT_OK) {
Bundle bundle = data.getExtras();
setEncryptionKeyIds(bundle
.getLongArray(SelectPublicKeyActivity.RESULT_EXTRA_MASTER_KEY_IDS));
setEncryptionUserIds(bundle.getStringArray(SelectPublicKeyActivity.RESULT_EXTRA_USER_IDS));
} }
break;
}
case REQUEST_CODE_SECRET_KEYS: { @Override
if (resultCode == Activity.RESULT_OK) { public void bindView(View view, Context context, Cursor cursor) {
Uri uriMasterKey = data.getData(); ((TextView) view.findViewById(android.R.id.text1)).setText(cursor.getString(mIndexUserId));
setSignatureKeyId(Long.valueOf(uriMasterKey.getLastPathSegment())); view.findViewById(android.R.id.text2).setVisibility(View.VISIBLE);
((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)));
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(mIndexMasterKeyId);
}
};
}
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == null) return inner.swapCursor(null);
mIndexKeyId = newCursor.getColumnIndex(KeyRings.KEY_ID);
mIndexUserId = newCursor.getColumnIndex(KeyRings.USER_ID);
mIndexMasterKeyId = newCursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
if (newCursor.moveToFirst()) {
do {
if (newCursor.getLong(mIndexMasterKeyId) == mEncryptInterface.getSignatureKey()) {
mSign.setSelection(newCursor.getPosition() + 1);
}
} while (newCursor.moveToNext());
}
return inner.swapCursor(newCursor);
}
@Override
public int getCount() {
return inner.getCount() + 1;
}
@Override
public Object getItem(int position) {
if (position == 0) return null;
return inner.getItem(position - 1);
}
@Override
public long getItemId(int position) {
if (position == 0) return Constants.key.none;
return inner.getItemId(position - 1);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
View v;
if (convertView == null) {
v = inner.newView(null, null, parent);
} else { } else {
setSignatureKeyId(Constants.key.none); v = convertView;
} }
break; ((TextView) v.findViewById(android.R.id.text1)).setText("None");
} v.findViewById(android.R.id.text2).setVisibility(View.GONE);
return v;
default: { } else {
super.onActivityResult(requestCode, resultCode, data); return inner.getView(position - 1, convertView, parent);
break;
} }
} }
} }

View File

@ -18,44 +18,28 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Point; import android.graphics.Point;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.app.Fragment; 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 android.widget.*; import android.widget.*;
import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Choice; import org.sufficientlysecure.keychain.util.Choice;
import org.sufficientlysecure.keychain.util.Log;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public class EncryptFileFragment extends Fragment { public class EncryptFileFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
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;
@ -64,15 +48,11 @@ public class EncryptFileFragment extends Fragment {
private EncryptActivityInterface mEncryptInterface; private EncryptActivityInterface mEncryptInterface;
// view // view
private Spinner mFileCompression = null; private View mAddView;
private View mShareFile; private View mShareFile;
private View mEncryptFile; private View mEncryptFile;
private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter();
// model
private ArrayList<Uri> mInputUri = new ArrayList<Uri>();
private ArrayList<Uri> mOutputUri = new ArrayList<Uri>();
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
@ -105,34 +85,23 @@ public class EncryptFileFragment extends Fragment {
} }
}); });
//mFilename = (TextView) view.findViewById(R.id.filename); mAddView = inflater.inflate(R.layout.file_list_entry_add, null);
//view.findViewById(R.id.btn_browse).setOnClickListener(new View.OnClickListener() { mAddView.setOnClickListener(new View.OnClickListener() {
// public void onClick(View v) {
// if (Constants.KITKAT) {
// FileHelper.openDocument(EncryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);
// } else {
// FileHelper.openFile(EncryptFileFragment.this,
// mInputUri.isEmpty() ? null : mInputUri.get(mInputUri.size() - 1), "*/*", REQUEST_CODE_INPUT);
// }
// }
//});
View addFile = inflater.inflate(R.layout.file_list_entry_add, null);
addFile.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (Constants.KITKAT) { if (Constants.KITKAT) {
FileHelper.openDocument(EncryptFileFragment.this, "*/*", REQUEST_CODE_INPUT); FileHelper.openDocument(EncryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);
} else { } else {
FileHelper.openFile(EncryptFileFragment.this, FileHelper.openFile(EncryptFileFragment.this,
mInputUri.isEmpty() ? null : mInputUri.get(mInputUri.size() - 1), "*/*", REQUEST_CODE_INPUT); mEncryptInterface.getInputUris().isEmpty() ? null : mEncryptInterface.getInputUris().get(mEncryptInterface.getInputUris().size() - 1), "*/*", REQUEST_CODE_INPUT);
} }
} }
}); });
ListView listView = (ListView) view.findViewById(R.id.selected_files_list); ListView listView = (ListView) view.findViewById(R.id.selected_files_list);
listView.addFooterView(addFile); listView.addFooterView(mAddView);
listView.setAdapter(mAdapter); listView.setAdapter(mAdapter);
/*
mFileCompression = (Spinner) view.findViewById(R.id.fileCompression); mFileCompression = (Spinner) view.findViewById(R.id.fileCompression);
Choice[] choices = new Choice[]{ Choice[] choices = new Choice[]{
new Choice(Constants.choice.compression.none, getString(R.string.choice_none) + " (" new Choice(Constants.choice.compression.none, getString(R.string.choice_none) + " ("
@ -149,6 +118,7 @@ public class EncryptFileFragment extends Fragment {
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mFileCompression.setAdapter(adapter); mFileCompression.setAdapter(adapter);
int defaultFileCompression = Preferences.getPreferences(getActivity()).getDefaultFileCompression(); int defaultFileCompression = Preferences.getPreferences(getActivity()).getDefaultFileCompression();
for (int i = 0; i < choices.length; ++i) { for (int i = 0; i < choices.length; ++i) {
if (choices[i].getId() == defaultFileCompression) { if (choices[i].getId() == defaultFileCompression) {
@ -156,6 +126,7 @@ public class EncryptFileFragment extends Fragment {
break; break;
} }
} }
*/
return view; return view;
} }
@ -180,20 +151,39 @@ public class EncryptFileFragment extends Fragment {
return; return;
} }
mInputUri.add(inputUri); mEncryptInterface.getInputUris().add(inputUri);
mAdapter.notifyDataSetChanged(); mEncryptInterface.notifyUpdate();
/**
* We hide the encrypt to file button if multiple files are selected.
*
* With Android L it will be possible to select a target directory for multiple files, so we might want to
* change this later
*/
if (mEncryptInterface.getInputUris().size() > 1) {
mEncryptFile.setVisibility(View.GONE);
} else {
mEncryptFile.setVisibility(View.VISIBLE);
}
} }
private void delInputUri(int position) { private void delInputUri(int position) {
mInputUri.remove(position); mEncryptInterface.getInputUris().remove(position);
mAdapter.notifyDataSetChanged(); mEncryptInterface.notifyUpdate();
if (mEncryptInterface.getInputUris().size() > 1) {
mEncryptFile.setVisibility(View.GONE);
} else {
mEncryptFile.setVisibility(View.VISIBLE);
}
} }
private void showOutputFileDialog() { private void showOutputFileDialog() {
if (mInputUri.size() > 1 || mInputUri.isEmpty()) { if (mEncryptInterface.getInputUris().size() > 1 || mEncryptInterface.getInputUris().isEmpty()) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
Uri inputUri = mInputUri.get(0); Uri inputUri = mEncryptInterface.getInputUris().get(0);
if (!Constants.KITKAT) { if (!Constants.KITKAT) {
File file = new File(inputUri.getPath()); File file = new File(inputUri.getPath());
File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR; File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
@ -209,176 +199,19 @@ public class EncryptFileFragment extends Fragment {
} }
private void encryptClicked(boolean share) { private void encryptClicked(boolean share) {
if (mInputUri.isEmpty()) {
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
return;
} else if (mInputUri.size() > 1 && !share) {
AppMsg.makeText(getActivity(), "TODO", AppMsg.STYLE_ALERT).show(); // TODO
return;
}
if (mEncryptInterface.isModeSymmetric()) {
// symmetric encryption
boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
&& mEncryptInterface.getPassphrase().length() != 0);
if (!gotPassphrase) {
AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
.show();
return;
}
if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
return;
}
} else {
// asymmetric encryption
boolean gotEncryptionKeys = (mEncryptInterface.getEncryptionKeys() != null
&& mEncryptInterface.getEncryptionKeys().length > 0);
if (!gotEncryptionKeys) {
AppMsg.makeText(getActivity(), R.string.select_encryption_key, AppMsg.STYLE_ALERT).show();
return;
}
if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) {
AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key,
AppMsg.STYLE_ALERT).show();
return;
}
if (mEncryptInterface.getSignatureKey() != 0 &&
PassphraseCacheService.getCachedPassphrase(getActivity(),
mEncryptInterface.getSignatureKey()) == null) {
PassphraseDialogFragment.show(getActivity(), mEncryptInterface.getSignatureKey(),
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
showOutputFileDialog();
}
}
});
return;
}
}
if (share) { if (share) {
mOutputUri.clear(); mEncryptInterface.getOutputUris().clear();
for (Uri uri : mInputUri) { for (Uri uri : mEncryptInterface.getInputUris()) {
String targetName = FileHelper.getFilename(getActivity(), uri) + String targetName = FileHelper.getFilename(getActivity(), uri) +
(mEncryptInterface.isUseArmor() ? ".asc" : ".gpg"); (mEncryptInterface.isUseArmor() ? ".asc" : ".gpg");
mOutputUri.add(TemporaryStorageProvider.createFile(getActivity(), targetName)); mEncryptInterface.getOutputUris().add(TemporaryStorageProvider.createFile(getActivity(), targetName));
} }
encryptStart(true); mEncryptInterface.startEncrypt(share);
} else if (mInputUri.size() == 1) { } else if (mEncryptInterface.getInputUris().size() == 1) {
showOutputFileDialog(); showOutputFileDialog();
} }
} }
private void encryptStart(final boolean share) {
if (mInputUri == null || mOutputUri == null || mInputUri.size() != mOutputUri.size()) {
throw new IllegalStateException("Something went terribly wrong if this happens!");
}
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
// fill values for this action
Bundle data = new Bundle();
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URIS);
data.putParcelableArrayList(KeychainIntentService.ENCRYPT_INPUT_URIS, mInputUri);
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URIS);
data.putParcelableArrayList(KeychainIntentService.ENCRYPT_OUTPUT_URIS, mOutputUri);
if (mEncryptInterface.isModeSymmetric()) {
Log.d(Constants.TAG, "Symmetric encryption enabled!");
String passphrase = mEncryptInterface.getPassphrase();
if (passphrase.length() == 0) {
passphrase = null;
}
data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase);
} else {
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID,
mEncryptInterface.getSignatureKey());
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS,
mEncryptInterface.getEncryptionKeys());
}
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, mEncryptInterface.isUseArmor());
int compressionId = ((Choice) mFileCompression.getSelectedItem()).getId();
data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Message is received after encrypting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
AppMsg.makeText(getActivity(), R.string.encrypt_sign_successful,
AppMsg.STYLE_INFO).show();
if (mEncryptInterface.isDeleteAfterEncrypt()) {
// Create and show dialog to delete original file
/*DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
setInputUri(null);*/
}
if (share) {
// Share encrypted file
Intent sendFileIntent;
if (mOutputUri.size() == 1) {
sendFileIntent = new Intent(Intent.ACTION_SEND);
sendFileIntent.setType("*/*");
sendFileIntent.putExtra(Intent.EXTRA_STREAM, mOutputUri.get(0));
} else {
sendFileIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
sendFileIntent.setType("*/*");
sendFileIntent.putExtra(Intent.EXTRA_STREAM, mOutputUri);
}
if (!mEncryptInterface.isModeSymmetric() && mEncryptInterface.getEncryptionUsers() != null) {
Set<String> users = new HashSet<String>();
for (String user : mEncryptInterface.getEncryptionUsers()) {
String[] userId = KeyRing.splitUserId(user);
if (userId[1] != null) {
users.add(userId[1]);
}
}
sendFileIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
startActivity(Intent.createChooser(sendFileIntent,
getString(R.string.title_share_file)));
}
}
}
};
// 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);
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { switch (requestCode) {
@ -391,8 +224,8 @@ public class EncryptFileFragment extends Fragment {
case REQUEST_CODE_OUTPUT: { case REQUEST_CODE_OUTPUT: {
// This happens after output file was selected, so start our operation // This happens after output file was selected, so start our operation
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
mOutputUri.add(data.getData()); mEncryptInterface.getOutputUris().add(data.getData());
encryptStart(false); mEncryptInterface.startEncrypt(false);
} }
return; return;
} }
@ -405,15 +238,20 @@ public class EncryptFileFragment extends Fragment {
} }
} }
@Override
public void onNotifyUpdate() {
mAdapter.notifyDataSetChanged();
}
private class SelectedFilesAdapter extends BaseAdapter { private class SelectedFilesAdapter extends BaseAdapter {
@Override @Override
public int getCount() { public int getCount() {
return mInputUri.size(); return mEncryptInterface.getInputUris().size();
} }
@Override @Override
public Object getItem(int position) { public Object getItem(int position) {
return mInputUri.get(position); return mEncryptInterface.getInputUris().get(position);
} }
@Override @Override
@ -429,8 +267,8 @@ public class EncryptFileFragment extends Fragment {
} else { } else {
view = convertView; view = convertView;
} }
((TextView) view.findViewById(R.id.filename)).setText(FileHelper.getFilename(getActivity(), mInputUri.get(position))); ((TextView) view.findViewById(R.id.filename)).setText(FileHelper.getFilename(getActivity(), mEncryptInterface.getInputUris().get(position)));
long size = FileHelper.getFileSize(getActivity(), mInputUri.get(position)); long size = FileHelper.getFileSize(getActivity(), mEncryptInterface.getInputUris().get(position));
if (size == -1) { if (size == -1) {
((TextView) view.findViewById(R.id.filesize)).setText(""); ((TextView) view.findViewById(R.id.filesize)).setText("");
} else { } else {
@ -443,7 +281,7 @@ public class EncryptFileFragment extends Fragment {
} }
}); });
int px = OtherHelper.dpToPx(getActivity(), 48); int px = OtherHelper.dpToPx(getActivity(), 48);
Bitmap bitmap = FileHelper.getThumbnail(getActivity(), mInputUri.get(position), new Point(px, px)); Bitmap bitmap = FileHelper.getThumbnail(getActivity(), mEncryptInterface.getInputUris().get(position), new Point(px, px));
if (bitmap != null) { if (bitmap != null) {
((ImageView) view.findViewById(R.id.thumbnail)).setImageBitmap(bitmap); ((ImageView) view.findViewById(R.id.thumbnail)).setImageBitmap(bitmap);
} else { } else {

View File

@ -25,6 +25,8 @@ import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.support.v4.app.Fragment; 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;
@ -75,18 +77,34 @@ public class EncryptMessageFragment extends Fragment {
View view = inflater.inflate(R.layout.encrypt_message_fragment, container, false); View view = inflater.inflate(R.layout.encrypt_message_fragment, container, false);
mMessage = (TextView) view.findViewById(R.id.message); mMessage = (TextView) view.findViewById(R.id.message);
mMessage.addTextChangedListener(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) {
mEncryptInterface.setMessage(s.toString());
}
});
mEncryptClipboard = view.findViewById(R.id.action_encrypt_clipboard); mEncryptClipboard = view.findViewById(R.id.action_encrypt_clipboard);
mEncryptShare = view.findViewById(R.id.action_encrypt_share); mEncryptShare = view.findViewById(R.id.action_encrypt_share);
mEncryptClipboard.setOnClickListener(new View.OnClickListener() { mEncryptClipboard.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
encryptClicked(true); mEncryptInterface.startEncrypt(false);
} }
}); });
mEncryptShare.setOnClickListener(new View.OnClickListener() { mEncryptShare.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
encryptClicked(false); mEncryptInterface.startEncrypt(true);
} }
}); });
@ -98,7 +116,7 @@ public class EncryptMessageFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
String text = getArguments().getString(ARG_TEXT); String text = mEncryptInterface.getMessage();
if (text != null) { if (text != null) {
mMessage.setText(text); mMessage.setText(text);
} }
@ -123,150 +141,4 @@ public class EncryptMessageFragment extends Fragment {
return message; return message;
} }
private void encryptClicked(final boolean toClipboard) {
if (mEncryptInterface.isModeSymmetric()) {
// symmetric encryption
boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
&& mEncryptInterface.getPassphrase().length() != 0);
if (!gotPassphrase) {
AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
.show();
return;
}
if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
return;
}
} else {
// asymmetric encryption
boolean gotEncryptionKeys = (mEncryptInterface.getEncryptionKeys() != null
&& mEncryptInterface.getEncryptionKeys().length > 0);
if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) {
AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key,
AppMsg.STYLE_ALERT).show();
return;
}
if (mEncryptInterface.getSignatureKey() != 0 &&
PassphraseCacheService.getCachedPassphrase(getActivity(),
mEncryptInterface.getSignatureKey()) == null) {
PassphraseDialogFragment.show(getActivity(), mEncryptInterface.getSignatureKey(),
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
encryptStart(toClipboard);
}
}
});
return;
}
}
encryptStart(toClipboard);
}
private void encryptStart(final boolean toClipboard) {
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
// fill values for this action
Bundle data = new Bundle();
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
String message = mMessage.getText().toString();
if (mEncryptInterface.isModeSymmetric()) {
Log.d(Constants.TAG, "Symmetric encryption enabled!");
String passphrase = mEncryptInterface.getPassphrase();
if (passphrase.length() == 0) {
passphrase = null;
}
data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase);
} else {
data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID,
mEncryptInterface.getSignatureKey());
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS,
mEncryptInterface.getEncryptionKeys());
boolean signOnly = (mEncryptInterface.getEncryptionKeys() == null
|| mEncryptInterface.getEncryptionKeys().length == 0);
if (signOnly) {
message = fixBadCharactersForGmail(message);
}
}
data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, message.getBytes());
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, true);
int compressionId = Preferences.getPreferences(getActivity()).getDefaultMessageCompression();
data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Message is received after encrypting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
// get returned data bundle
Bundle data = message.getData();
String output = new String(data.getByteArray(KeychainIntentService.RESULT_BYTES));
Log.d(Constants.TAG, "output: " + output);
if (toClipboard) {
ClipboardReflection.copyToClipboard(getActivity(), output);
AppMsg.makeText(getActivity(),
R.string.encrypt_sign_clipboard_successful, AppMsg.STYLE_INFO)
.show();
} else {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
// Type is set to text/plain so that encrypted messages can
// be sent with Whatsapp, Hangouts, SMS etc...
sendIntent.setType("text/plain");
Log.d(Constants.TAG, "encrypt to:" + Arrays.toString(mEncryptInterface.getEncryptionUsers()));
if (!mEncryptInterface.isModeSymmetric() && mEncryptInterface.getEncryptionUsers() != null) {
Set<String> users = new HashSet<String>();
for (String user : mEncryptInterface.getEncryptionUsers()) {
String[] userId = KeyRing.splitUserId(user);
if (userId[1] != null) {
users.add(userId[1]);
}
}
sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
sendIntent.putExtra(Intent.EXTRA_TEXT, output);
startActivity(Intent.createChooser(sendIntent,
getString(R.string.title_share_with)));
}
}
}
};
// 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);
}
} }

View File

@ -29,27 +29,20 @@ import android.widget.EditText;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
public class EncryptSymmetricFragment extends Fragment { public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
OnSymmetricKeySelection mPassphraseUpdateListener; EncryptActivityInterface mEncryptInterface;
private EditText mPassphrase; private EditText mPassphrase;
private EditText mPassphraseAgain; private EditText mPassphraseAgain;
// Container Activity must implement this interface
public interface OnSymmetricKeySelection {
public void onPassphraseUpdate(String passphrase);
public void onPassphraseAgainUpdate(String passphrase);
}
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
try { try {
mPassphraseUpdateListener = (OnSymmetricKeySelection) activity; mEncryptInterface = (EncryptActivityInterface) activity;
} catch (ClassCastException e) { } catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnSymmetricKeySelection"); throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface");
} }
} }
@ -62,7 +55,7 @@ public class EncryptSymmetricFragment extends Fragment {
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);
mPassphrase.addTextChangedListener(new TextWatcher() { TextWatcher textWatcher = 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) {
} }
@ -74,25 +67,21 @@ public class EncryptSymmetricFragment extends Fragment {
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
// update passphrase in EncryptActivity // update passphrase in EncryptActivity
mPassphraseUpdateListener.onPassphraseUpdate(s.toString()); if (mPassphrase.getText().toString().equals(mPassphraseAgain.getText().toString())) {
mEncryptInterface.setPassphrase(s.toString());
} else {
mEncryptInterface.setPassphrase(null);
}
} }
}); };
mPassphraseAgain.addTextChangedListener(new TextWatcher() { mPassphrase.addTextChangedListener(textWatcher);
@Override mPassphraseAgain.addTextChangedListener(textWatcher);
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
mPassphraseUpdateListener.onPassphraseAgainUpdate(s.toString());
}
});
return view; return view;
} }
@Override
public void onNotifyUpdate() {
}
} }

View File

@ -43,7 +43,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
} }
private void initView() { private void initView() {
fromCursor(null); swapCursor(null);
setPrefix(getContext().getString(R.string.label_to) + ": "); setPrefix(getContext().getString(R.string.label_to) + ": ");
allowDuplicates(false); allowDuplicates(false);
} }
@ -81,7 +81,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
return null; return null;
} }
public void fromCursor(Cursor cursor) { public void swapCursor(Cursor cursor) {
if (cursor == null) { if (cursor == null) {
setAdapter(new EncryptKeyAdapter(Collections.<EncryptionKey>emptyList())); setAdapter(new EncryptKeyAdapter(Collections.<EncryptionKey>emptyList()));
return; return;

View File

@ -9,12 +9,31 @@
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingLeft="16dp"> android:paddingLeft="16dp">
<CheckBox <LinearLayout
android:id="@+id/sign" android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:padding="0dp"
android:text="@string/label_sign"/> android:layout_margin="0dp"
style="@android:style/Widget.EditText">
<TextView
android:paddingLeft="12dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="From: "/>
<Spinner
android:id="@+id/sign"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/label_sign"
android:padding="0dp"
android:layout_margin="0dp"
/>
</LinearLayout>
<org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView <org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView
android:id="@+id/recipient_list" android:id="@+id/recipient_list"

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:padding="8dp"
android:layout_height="wrap_content">
<TextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>

View File

@ -25,14 +25,6 @@
android:layout_height="0dip" android:layout_height="0dip"
android:layout_weight="1"/> android:layout_weight="1"/>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider"
android:layout_marginBottom="8dp"/>
<include layout="@layout/encrypt_content_adv_settings" />
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dip" android:layout_height="1dip"