mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-28 03:22:19 -05:00
Load of rework on EncryptActivity, still some TODOs
This commit is contained in:
parent
bc9922263c
commit
2913a78b18
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
|
@ -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>
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user