aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java182
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java397
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java322
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java471
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java166
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java45
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java85
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java88
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java232
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java45
16 files changed, 1175 insertions, 929 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index dba742268..e62591b1a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -23,11 +23,8 @@ import android.net.Uri;
import android.os.Bundle;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
-import android.widget.Toast;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.util.Log;
@@ -114,7 +111,7 @@ public class DecryptActivity extends DrawerActivity {
} else {
// Binary via content provider (could also be files)
// override uri to get stream from send
- uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
+ uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
action = ACTION_DECRYPT;
}
} else if (Intent.ACTION_VIEW.equals(action)) {
@@ -122,6 +119,7 @@ public class DecryptActivity extends DrawerActivity {
// override action
action = ACTION_DECRYPT;
+ mFileFragmentBundle.putBoolean(DecryptFileFragment.ARG_FROM_VIEW_INTENT, true);
}
String textData = extras.getString(EXTRA_TEXT);
@@ -155,21 +153,8 @@ public class DecryptActivity extends DrawerActivity {
}
}
} else if (ACTION_DECRYPT.equals(action) && uri != null) {
- // get file path from uri
- String path = FileHelper.getPath(this, uri);
-
- if (path != null) {
- mFileFragmentBundle.putString(DecryptFileFragment.ARG_FILENAME, path);
- mSwitchToTab = PAGER_TAB_FILE;
- } else {
- Log.e(Constants.TAG,
- "Direct binary data without actual file in filesystem is not supported. " +
- "Please use the Remote Service API!");
- Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG)
- .show();
- // end activity
- finish();
- }
+ mFileFragmentBundle.putParcelable(DecryptFileFragment.ARG_URI, uri);
+ mSwitchToTab = PAGER_TAB_FILE;
} else if (ACTION_DECRYPT.equals(action)) {
Log.e(Constants.TAG,
"Include the extra 'text' or an Uri with setData() in your Intent!");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java
index 56dfdbd95..5b61c3f52 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java
@@ -20,13 +20,10 @@ package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
-import android.provider.OpenableColumns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -34,37 +31,35 @@ import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
+import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.util.Notify;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.io.File;
public class DecryptFileFragment extends DecryptFragment {
- public static final String ARG_FILENAME = "filename";
+ public static final String ARG_URI = "uri";
+ public static final String ARG_FROM_VIEW_INTENT = "view_intent";
- private static final int RESULT_CODE_FILE = 0x00007003;
+ private static final int REQUEST_CODE_INPUT = 0x00007003;
+ private static final int REQUEST_CODE_OUTPUT = 0x00007007;
// view
- private EditText mFilename;
+ private TextView mFilename;
private CheckBox mDeleteAfter;
- private ImageButton mBrowse;
private View mDecryptButton;
- private String mInputFilename = null;
+ // model
private Uri mInputUri = null;
- private String mOutputFilename = null;
private Uri mOutputUri = null;
- private FileDialogFragment mFileDialog;
-
/**
* Inflate the layout for this fragment
*/
@@ -72,17 +67,16 @@ public class DecryptFileFragment extends DecryptFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.decrypt_file_fragment, container, false);
- mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename);
- mBrowse = (ImageButton) view.findViewById(R.id.decrypt_file_browse);
+ mFilename = (TextView) view.findViewById(R.id.decrypt_file_filename);
mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption);
mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt);
- mBrowse.setOnClickListener(new View.OnClickListener() {
+ view.findViewById(R.id.decrypt_file_browse).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Constants.KITKAT) {
- FileHelper.openDocument(DecryptFileFragment.this, mInputUri, "*/*", RESULT_CODE_FILE);
+ FileHelper.openDocument(DecryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);
} else {
- FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*",
- RESULT_CODE_FILE);
+ FileHelper.openFile(DecryptFileFragment.this, mInputUri, "*/*",
+ REQUEST_CODE_INPUT);
}
}
});
@@ -100,74 +94,47 @@ public class DecryptFileFragment extends DecryptFragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- String filename = getArguments().getString(ARG_FILENAME);
- if (filename != null) {
- mFilename.setText(filename);
- }
+ setInputUri(getArguments().<Uri>getParcelable(ARG_URI));
}
- private String guessOutputFilename() {
- File file = new File(mInputFilename);
- String filename = file.getName();
- if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) {
- filename = filename.substring(0, filename.length() - 4);
+ private void setInputUri(Uri inputUri) {
+ if (inputUri == null) {
+ mInputUri = null;
+ mFilename.setText("");
+ return;
}
- return Constants.Path.APP_DIR + "/" + filename;
+
+ mInputUri = inputUri;
+ mFilename.setText(FileHelper.getFilename(getActivity(), mInputUri));
}
private void decryptAction() {
- String currentFilename = mFilename.getText().toString();
- if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
- mInputUri = null;
- mInputFilename = mFilename.getText().toString();
- }
-
if (mInputUri == null) {
- mOutputFilename = guessOutputFilename();
- }
-
- if (mInputFilename.equals("")) {
Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR);
return;
}
- if (mInputUri == null && mInputFilename.startsWith("file")) {
- File file = new File(mInputFilename);
- if (!file.exists() || !file.isFile()) {
- Notify.showNotify(getActivity(), getString(R.string.error_message,
- getString(R.string.error_file_not_found)), Notify.Style.ERROR);
- return;
- }
- }
-
askForOutputFilename();
}
- private void askForOutputFilename() {
- // Message is received after passphrase is cached
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == FileDialogFragment.MESSAGE_OKAY) {
- Bundle data = message.getData();
- if (data.containsKey(FileDialogFragment.MESSAGE_DATA_URI)) {
- mOutputUri = data.getParcelable(FileDialogFragment.MESSAGE_DATA_URI);
- } else {
- mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
- }
- decryptStart(null);
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- mFileDialog = FileDialogFragment.newInstance(messenger,
- getString(R.string.title_decrypt_to_file),
- getString(R.string.specify_file_to_decrypt_to), mOutputFilename, null);
+ private String removeEncryptedAppend(String name) {
+ if (name.endsWith(".asc") || name.endsWith(".gpg") || name.endsWith(".pgp")) {
+ return name.substring(0, name.length() - 4);
+ }
+ return name;
+ }
- mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog");
+ private void askForOutputFilename() {
+ String targetName = removeEncryptedAppend(FileHelper.getFilename(getActivity(), mInputUri));
+ if (!Constants.KITKAT) {
+ File file = new File(mInputUri.getPath());
+ File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
+ File targetFile = new File(parentDir, targetName);
+ FileHelper.saveFile(this, getString(R.string.title_decrypt_to_file),
+ getString(R.string.specify_file_to_decrypt_to), targetFile, REQUEST_CODE_OUTPUT);
+ } else {
+ FileHelper.saveDocument(this, "*/*", targetName, REQUEST_CODE_OUTPUT);
+ }
}
@Override
@@ -183,25 +150,13 @@ public class DecryptFileFragment extends DecryptFragment {
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
// data
- Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
- + mOutputFilename + ",mInputUri=" + mInputUri + ", mOutputUri="
- + mOutputUri);
+ Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
- if (mInputUri != null) {
- data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
- data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
- } else {
- data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_FILE);
- data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
- }
+ data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
+ data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
- if (mOutputUri != null) {
- data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
- data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
- } else {
- data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_FILE);
- data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename);
- }
+ data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
+ data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
@@ -232,15 +187,19 @@ public class DecryptFileFragment extends DecryptFragment {
if (mDeleteAfter.isChecked()) {
// Create and show dialog to delete original file
- DeleteFileDialogFragment deleteFileDialog;
- if (mInputUri != null) {
- deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
- } else {
- deleteFileDialog = DeleteFileDialogFragment
- .newInstance(mInputFilename);
- }
+ DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
+ setInputUri(null);
}
+
+ /*
+ // A future open after decryption feature
+ if () {
+ Intent viewFile = new Intent(Intent.ACTION_VIEW);
+ viewFile.setData(mOutputUri);
+ startActivity(viewFile);
+ }
+ */
}
}
}
@@ -260,28 +219,17 @@ public class DecryptFileFragment extends DecryptFragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
- case RESULT_CODE_FILE: {
+ case REQUEST_CODE_INPUT: {
if (resultCode == Activity.RESULT_OK && data != null) {
- if (Constants.KITKAT) {
- mInputUri = data.getData();
- Cursor cursor = getActivity().getContentResolver().query(mInputUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
- if (cursor != null) {
- if (cursor.moveToNext()) {
- mInputFilename = cursor.getString(0);
- mFilename.setText(mInputFilename);
- }
- cursor.close();
- }
- } else {
- try {
- String path = FileHelper.getPath(getActivity(), data.getData());
- Log.d(Constants.TAG, "path=" + path);
-
- mFilename.setText(path);
- } catch (NullPointerException e) {
- Log.e(Constants.TAG, "Nullpointer while retrieving path!");
- }
- }
+ setInputUri(data.getData());
+ }
+ return;
+ }
+ case REQUEST_CODE_OUTPUT: {
+ // This happens after output file was selected, so start our operation
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ mOutputUri = data.getData();
+ decryptStart(null);
}
return;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
index d4235b82b..16a7b911e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
@@ -38,7 +38,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
-public class DecryptFragment extends Fragment {
+public abstract class DecryptFragment extends Fragment {
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
protected long mSignatureKeyId = 0;
@@ -217,8 +217,6 @@ public class DecryptFragment extends Fragment {
*
* @param passphrase
*/
- protected void decryptStart(String passphrase) {
-
- }
+ protected abstract void decryptStart(String passphrase);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index cc69148c1..3dea8f227 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -18,23 +18,37 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
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.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
-import android.widget.Toast;
-
+import android.view.Menu;
+import android.view.MenuItem;
+import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.FileHelper;
+import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
+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.dialog.DeleteFileDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-public class EncryptActivity extends DrawerActivity implements
- EncryptSymmetricFragment.OnSymmetricKeySelection,
- EncryptAsymmetricFragment.OnAsymmetricKeySelection,
- EncryptActivityInterface {
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class EncryptActivity extends DrawerActivity implements EncryptActivityInterface {
/* Intents */
public static final String ACTION_ENCRYPT = Constants.INTENT_PREFIX + "ENCRYPT";
@@ -51,7 +65,7 @@ public class EncryptActivity extends DrawerActivity implements
// view
ViewPager mViewPagerMode;
- PagerTabStrip mPagerTabStripMode;
+ //PagerTabStrip mPagerTabStripMode;
PagerTabStripAdapter mTabsAdapterMode;
ViewPager mViewPagerContent;
PagerTabStrip mPagerTabStripContent;
@@ -72,63 +86,309 @@ public class EncryptActivity extends DrawerActivity implements
// model used by message and file fragments
private long mEncryptionKeyIds[] = null;
+ private String mEncryptionUserIds[] = null;
private long mSigningKeyId = Constants.key.none;
- private String mPassphrase;
- private String mPassphraseAgain;
+ private String mPassphrase = "";
+ private boolean mUseArmor;
+ private boolean mDeleteAfterEncrypt = false;
+ private boolean mShareAfterEncrypt = false;
+ private ArrayList<Uri> mInputUris;
+ private ArrayList<Uri> mOutputUris;
+ private String mMessage;
+
+ public boolean isModeSymmetric() {
+ return PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem();
+ }
+
+ public boolean isContentMessage() {
+ return PAGER_CONTENT_MESSAGE == mViewPagerContent.getCurrentItem();
+ }
@Override
- public void onSigningKeySelected(long signingKeyId) {
- mSigningKeyId = signingKeyId;
+ public boolean isUseArmor() {
+ return mUseArmor;
}
@Override
- public void onEncryptionKeysSelected(long[] encryptionKeyIds) {
- mEncryptionKeyIds = encryptionKeyIds;
+ public long getSignatureKey() {
+ return mSigningKeyId;
+ }
+
+ @Override
+ public long[] getEncryptionKeys() {
+ return mEncryptionKeyIds;
}
@Override
- public void onPassphraseUpdate(String passphrase) {
+ public String[] getEncryptionUsers() {
+ return mEncryptionUserIds;
+ }
+
+ @Override
+ public void setSignatureKey(long signatureKey) {
+ mSigningKeyId = signatureKey;
+ notifyUpdate();
+ }
+
+ @Override
+ public void setEncryptionKeys(long[] encryptionKeys) {
+ mEncryptionKeyIds = encryptionKeys;
+ notifyUpdate();
+ }
+
+ @Override
+ public void setEncryptionUsers(String[] encryptionUsers) {
+ mEncryptionUserIds = encryptionUsers;
+ notifyUpdate();
+ }
+
+ @Override
+ public void setPassphrase(String passphrase) {
mPassphrase = passphrase;
}
@Override
- public void onPassphraseAgainUpdate(String passphrase) {
- mPassphraseAgain = passphrase;
+ public ArrayList<Uri> getInputUris() {
+ if (mInputUris == null) mInputUris = new ArrayList<Uri>();
+ return mInputUris;
}
@Override
- public boolean isModeSymmetric() {
- if (PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem()) {
- return true;
- } else {
- return false;
- }
+ public ArrayList<Uri> getOutputUris() {
+ if (mOutputUris == null) mOutputUris = new ArrayList<Uri>();
+ return mOutputUris;
}
@Override
- public long getSignatureKey() {
- return mSigningKeyId;
+ public void setInputUris(ArrayList<Uri> uris) {
+ mInputUris = uris;
+ notifyUpdate();
}
@Override
- public long[] getEncryptionKeys() {
- return mEncryptionKeyIds;
+ public void setOutputUris(ArrayList<Uri> uris) {
+ mOutputUris = uris;
+ notifyUpdate();
+ }
+
+ @Override
+ public String getMessage() {
+ return mMessage;
}
@Override
- public String getPassphrase() {
- return mPassphrase;
+ 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 String getPassphraseAgain() {
- return mPassphraseAgain;
+ 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
+ for (Uri inputUri : mInputUris) {
+ DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUri);
+ deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
+ }
+ mInputUris.clear();
+ notifyUpdate();
+ }
+
+ 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) {
+ // This should be impossible...
+ return false;
+ } else if (mInputUris.size() != mOutputUris.size()) {
+ // This as well
+ return false;
+ }
+ }
+
+ 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() {
mViewPagerMode = (ViewPager) findViewById(R.id.encrypt_pager_mode);
- mPagerTabStripMode = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_mode);
+ //mPagerTabStripMode = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_mode);
mViewPagerContent = (ViewPager) findViewById(R.id.encrypt_pager_content);
mPagerTabStripContent = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_content);
@@ -167,6 +427,41 @@ public class EncryptActivity extends DrawerActivity implements
mTabsAdapterContent.addTab(EncryptFileFragment.class,
mFileFragmentBundle, getString(R.string.label_file));
mViewPagerContent.setCurrentItem(mSwitchToContent);
+
+ mUseArmor = Preferences.getPreferences(this).getDefaultAsciiArmor();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.encrypt_activity, menu);
+ menu.findItem(R.id.check_use_armor).setChecked(mUseArmor);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.isCheckable()) {
+ item.setChecked(!item.isChecked());
+ }
+ switch (item.getItemId()) {
+ case R.id.check_use_symmetric:
+ mSwitchToMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC;
+
+ mViewPagerMode.setCurrentItem(mSwitchToMode);
+ notifyUpdate();
+ break;
+ case R.id.check_use_armor:
+ mUseArmor = item.isChecked();
+ notifyUpdate();
+ break;
+ case R.id.check_delete_after_encrypt:
+ mDeleteAfterEncrypt = item.isChecked();
+ notifyUpdate();
+ break;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ return true;
}
/**
@@ -178,12 +473,16 @@ public class EncryptActivity extends DrawerActivity implements
String action = intent.getAction();
Bundle extras = intent.getExtras();
String type = intent.getType();
- Uri uri = intent.getData();
+ ArrayList<Uri> uris = new ArrayList<Uri>();
if (extras == null) {
extras = new Bundle();
}
+ if (intent.getData() != null) {
+ uris.add(intent.getData());
+ }
+
/*
* Android's Action
*/
@@ -201,14 +500,19 @@ public class EncryptActivity extends DrawerActivity implements
}
} else {
// Files via content provider, override uri and action
- uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
+ uris.clear();
+ uris.add(intent.<Uri>getParcelableExtra(Intent.EXTRA_STREAM));
action = ACTION_ENCRYPT;
}
}
+ if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
+ uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ action = ACTION_ENCRYPT;
+ }
+
if (extras.containsKey(EXTRA_ASCII_ARMOR)) {
- boolean requestAsciiArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, true);
- mFileFragmentBundle.putBoolean(EncryptFileFragment.ARG_ASCII_ARMOR, requestAsciiArmor);
+ mUseArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, true);
}
String textData = extras.getString(EXTRA_TEXT);
@@ -230,25 +534,10 @@ public class EncryptActivity extends DrawerActivity implements
// encrypt text based on given extra
mMessageFragmentBundle.putString(EncryptMessageFragment.ARG_TEXT, textData);
mSwitchToContent = PAGER_CONTENT_MESSAGE;
- } else if (ACTION_ENCRYPT.equals(action) && uri != null) {
+ } else if (ACTION_ENCRYPT.equals(action) && uris != null && !uris.isEmpty()) {
// encrypt file based on Uri
-
- // get file path from uri
- String path = FileHelper.getPath(this, uri);
-
- if (path != null) {
- mFileFragmentBundle.putString(EncryptFileFragment.ARG_FILENAME, path);
- mSwitchToContent = PAGER_CONTENT_FILE;
- } else {
- Log.e(Constants.TAG,
- "Direct binary data without actual file in filesystem is not supported " +
- "by Intents. Please use the Remote Service API!"
- );
- Toast.makeText(this, R.string.error_only_files_are_supported,
- Toast.LENGTH_LONG).show();
- // end activity
- finish();
- }
+ mFileFragmentBundle.putParcelableArrayList(EncryptFileFragment.ARG_URIS, uris);
+ mSwitchToContent = PAGER_CONTENT_FILE;
} else if (ACTION_ENCRYPT.equals(action)) {
Log.e(Constants.TAG,
"Include the extra 'text' or an Uri with setData() in your Intent!");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java
index 0786b3a16..54fe369a7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java
@@ -17,14 +17,41 @@
package org.sufficientlysecure.keychain.ui;
+import android.net.Uri;
+
+import java.util.ArrayList;
+
public interface EncryptActivityInterface {
- public boolean isModeSymmetric();
+ public interface UpdateListener {
+ void onNotifyUpdate();
+ }
+
+ public boolean isUseArmor();
public long getSignatureKey();
public long[] getEncryptionKeys();
+ public String[] getEncryptionUsers();
+ public void setSignatureKey(long signatureKey);
+ public void setEncryptionKeys(long[] encryptionKeys);
+ public void setEncryptionUsers(String[] encryptionUsers);
+
+ public void setPassphrase(String passphrase);
+
+ // ArrayList on purpose as only those are parcelable
+ 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);
- public String getPassphrase();
- public String getPassphraseAgain();
+ /**
+ * 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);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index dc0510189..47f4bdf59 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -18,77 +18,73 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
-import android.content.Intent;
+import android.content.Context;
+import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.TextView;
-import android.widget.Button;
-
+import android.widget.*;
+import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
import org.sufficientlysecure.keychain.util.Log;
-import java.util.Vector;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
-public class EncryptAsymmetricFragment extends Fragment {
+public class EncryptAsymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
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 int REQUEST_CODE_PUBLIC_KEYS = 0x00007001;
- public static final int REQUEST_CODE_SECRET_KEYS = 0x00007002;
-
ProviderHelper mProviderHelper;
- OnAsymmetricKeySelection mKeySelectionListener;
-
// view
- private Button mSelectKeysButton;
- private CheckBox mSign;
- private TextView mMainUserId;
- private TextView mMainUserIdRest;
+ private Spinner mSign;
+ private EncryptKeyCompletionView mEncryptKeyView;
+ private SelectSignKeyCursorAdapter mSignAdapter = new SelectSignKeyCursorAdapter();
// model
- private long mSecretKeyId = Constants.key.none;
- private long mEncryptionKeyIds[] = null;
+ private EncryptActivityInterface mEncryptInterface;
- // Container Activity must implement this interface
- public interface OnAsymmetricKeySelection {
- public void onSigningKeySelected(long signingKeyId);
+ @Override
+ public void onNotifyUpdate() {
- public void onEncryptionKeysSelected(long[] encryptionKeyIds);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
- mKeySelectionListener = (OnAsymmetricKeySelection) activity;
+ mEncryptInterface = (EncryptActivityInterface) activity;
} catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implement OnAsymmetricKeySelection");
+ throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface");
}
}
private void setSignatureKeyId(long signatureKeyId) {
- mSecretKeyId = signatureKeyId;
- // update key selection in EncryptActivity
- mKeySelectionListener.onSigningKeySelected(signatureKeyId);
- updateView();
+ mEncryptInterface.setSignatureKey(signatureKeyId);
}
private void setEncryptionKeyIds(long[] encryptionKeyIds) {
- mEncryptionKeyIds = encryptionKeyIds;
- // update key selection in EncryptActivity
- mKeySelectionListener.onEncryptionKeysSelected(encryptionKeyIds);
- updateView();
+ mEncryptInterface.setEncryptionKeys(encryptionKeyIds);
+ }
+
+ private void setEncryptionUserIds(String[] encryptionUserIds) {
+ mEncryptInterface.setEncryptionUsers(encryptionUserIds);
}
/**
@@ -98,25 +94,20 @@ public class EncryptAsymmetricFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
- mSelectKeysButton = (Button) view.findViewById(R.id.btn_selectEncryptKeys);
- mSign = (CheckBox) view.findViewById(R.id.sign);
- mMainUserId = (TextView) view.findViewById(R.id.mainUserId);
- mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- mSelectKeysButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- selectPublicKeys();
+ mSign = (Spinner) view.findViewById(R.id.sign);
+ mSign.setAdapter(mSignAdapter);
+ mSign.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ setSignatureKeyId(parent.getAdapter().getItemId(position));
}
- });
- mSign.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- CheckBox checkBox = (CheckBox) v;
- if (checkBox.isChecked()) {
- selectSecretKey();
- } else {
- setSignatureKeyId(Constants.key.none);
- }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ setSignatureKeyId(Constants.key.none);
}
});
+ mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list);
return view;
}
@@ -132,6 +123,65 @@ public class EncryptAsymmetricFragment extends Fragment {
// preselect keys given by arguments (given by Intent to EncryptActivity)
preselectKeys(signatureKeyId, encryptionKeyIds, mProviderHelper);
+
+ 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() {
+ @Override
+ public void onTokenAdded(Object token) {
+ if (token instanceof EncryptKeyCompletionView.EncryptionKey) {
+ updateEncryptionKeys();
+ }
+ }
+
+ @Override
+ public void onTokenRemoved(Object token) {
+ if (token instanceof EncryptKeyCompletionView.EncryptionKey) {
+ updateEncryptionKeys();
+ }
+ }
+ });
}
/**
@@ -158,115 +208,113 @@ public class EncryptAsymmetricFragment extends Fragment {
}
if (preselectedEncryptionKeyIds != null) {
- Vector<Long> goodIds = new Vector<Long>();
- for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
+ for (long preselectedId : preselectedEncryptionKeyIds) {
try {
- long id = providerHelper.getCachedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
- preselectedEncryptionKeyIds[i])
- ).getMasterKeyId();
- goodIds.add(id);
+ CachedPublicKeyRing ring = providerHelper.getCachedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId));
+ mEncryptKeyView.addObject(mEncryptKeyView.new EncryptionKey(ring));
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);
}
}
- if (goodIds.size() > 0) {
- long[] keyIds = new long[goodIds.size()];
- for (int i = 0; i < goodIds.size(); ++i) {
- keyIds[i] = goodIds.get(i);
- }
- setEncryptionKeyIds(keyIds);
- }
- }
- }
-
- 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);
- mMainUserId.setText("");
- mMainUserIdRest.setText("");
- } else {
- // See if we can get a user_id from a unified query
- String[] userId;
- try {
- userId = mProviderHelper.getCachedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingUri(mSecretKeyId)).getSplitPrimaryUserIdWithFallback();
- } catch (PgpGeneralException e) {
- userId = null;
- }
- if (userId != null && userId[0] != null) {
- mMainUserId.setText(String.format("%#16x", Long.parseLong(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);
+ updateEncryptionKeys();
}
}
- private void selectPublicKeys() {
- Intent intent = new Intent(getActivity(), SelectPublicKeyActivity.class);
- Vector<Long> keyIds = new Vector<Long>();
- if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) {
- for (int i = 0; i < mEncryptionKeyIds.length; ++i) {
- keyIds.add(mEncryptionKeyIds[i]);
+ private void updateEncryptionKeys() {
+ List<Object> objects = mEncryptKeyView.getObjects();
+ List<Long> keyIds = new ArrayList<Long>();
+ List<String> userIds = new ArrayList<String>();
+ for (Object object : objects) {
+ if (object instanceof EncryptKeyCompletionView.EncryptionKey) {
+ keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId());
+ userIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getUserId());
}
}
- 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);
- }
+ long[] keyIdsArr = new long[keyIds.size()];
+ Iterator<Long> iterator = keyIds.iterator();
+ for (int i = 0; i < keyIds.size(); i++) {
+ keyIdsArr[i] = iterator.next();
}
- intent.putExtra(SelectPublicKeyActivity.EXTRA_SELECTED_MASTER_KEY_IDS, initialKeyIds);
- startActivityForResult(intent, REQUEST_CODE_PUBLIC_KEYS);
+ setEncryptionKeyIds(keyIdsArr);
+ setEncryptionUserIds(userIds.toArray(new String[userIds.size()]));
}
- private void selectSecretKey() {
- Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class);
- intent.putExtra(SelectSecretKeyActivity.EXTRA_FILTER_SIGN, true);
- startActivityForResult(intent, REQUEST_CODE_SECRET_KEYS);
- }
+ private class SelectSignKeyCursorAdapter extends BaseAdapter implements SpinnerAdapter {
+ private CursorAdapter inner;
+ private int mIndexUserId;
+ private int mIndexKeyId;
+ private int mIndexMasterKeyId;
+
+ public SelectSignKeyCursorAdapter() {
+ inner = new CursorAdapter(null, null, 0) {
+ @Override
+ 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));
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ ((TextView) view.findViewById(android.R.id.text1)).setText(cursor.getString(mIndexUserId));
+ view.findViewById(android.R.id.text2).setVisibility(View.VISIBLE);
+ ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)));
}
- break;
- }
- case REQUEST_CODE_SECRET_KEYS: {
- if (resultCode == Activity.RESULT_OK) {
- Uri uriMasterKey = data.getData();
- setSignatureKeyId(Long.valueOf(uriMasterKey.getLastPathSegment()));
- } else {
- setSignatureKeyId(Constants.key.none);
+ @Override
+ public long getItemId(int position) {
+ mCursor.moveToPosition(position);
+ return mCursor.getLong(mIndexMasterKeyId);
}
- break;
+ };
+ }
+
+ 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);
+ }
- default: {
- super.onActivityResult(requestCode, resultCode, data);
+ @Override
+ public int getCount() {
+ return inner.getCount() + 1;
+ }
- break;
+ @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 {
+ v = convertView;
+ }
+ ((TextView) v.findViewById(android.R.id.text1)).setText("None");
+ v.findViewById(android.R.id.text2).setVisibility(View.GONE);
+ return v;
+ } else {
+ return inner.getView(position - 1, convertView, parent);
}
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java
index 345e38a0e..1125dce77 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java
@@ -17,66 +17,44 @@
package org.sufficientlysecure.keychain.ui;
+import android.annotation.TargetApi;
import android.app.Activity;
-import android.app.ProgressDialog;
import android.content.Intent;
-import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Point;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.provider.OpenableColumns;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.Spinner;
-
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
-import org.sufficientlysecure.keychain.util.Choice;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.Notify;
+import org.sufficientlysecure.keychain.helper.OtherHelper;
+import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import java.io.File;
+import java.util.List;
-public class EncryptFileFragment extends Fragment {
- public static final String ARG_FILENAME = "filename";
- public static final String ARG_ASCII_ARMOR = "ascii_armor";
+public class EncryptFileFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
+ public static final String ARG_URIS = "uris";
- private static final int REQUEST_CODE_FILE = 0x00007003;
+ private static final int REQUEST_CODE_INPUT = 0x00007003;
+ private static final int REQUEST_CODE_OUTPUT = 0x00007007;
private EncryptActivityInterface mEncryptInterface;
// view
- private CheckBox mAsciiArmor = null;
- private Spinner mFileCompression = null;
- private EditText mFilename = null;
- private CheckBox mDeleteAfter = null;
- private CheckBox mShareAfter = null;
- private ImageButton mBrowse = null;
+ private View mAddView;
+ private View mShareFile;
private View mEncryptFile;
-
- private FileDialogFragment mFileDialog;
-
- // model
- private String mInputFilename = null;
- private Uri mInputUri = null;
- private String mOutputFilename = null;
- private Uri mOutputUri = null;
+ private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter();
@Override
public void onAttach(Activity activity) {
@@ -99,52 +77,27 @@ public class EncryptFileFragment extends Fragment {
mEncryptFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- encryptClicked();
+ encryptClicked(false);
}
});
-
- mFilename = (EditText) view.findViewById(R.id.filename);
- mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
- mBrowse.setOnClickListener(new View.OnClickListener() {
+ mShareFile = view.findViewById(R.id.action_encrypt_share);
+ mShareFile.setOnClickListener(new View.OnClickListener() {
+ @Override
public void onClick(View v) {
- if (Constants.KITKAT) {
- FileHelper.openDocument(EncryptFileFragment.this, mInputUri, "*/*", REQUEST_CODE_FILE);
- } else {
- FileHelper.openFile(EncryptFileFragment.this, mFilename.getText().toString(), "*/*",
- REQUEST_CODE_FILE);
- }
+ encryptClicked(true);
}
});
- mFileCompression = (Spinner) view.findViewById(R.id.fileCompression);
- Choice[] choices = new Choice[]{
- new Choice(Constants.choice.compression.none, getString(R.string.choice_none) + " ("
- + getString(R.string.compression_fast) + ")"),
- new Choice(Constants.choice.compression.zip, "ZIP ("
- + getString(R.string.compression_fast) + ")"),
- new Choice(Constants.choice.compression.zlib, "ZLIB ("
- + getString(R.string.compression_fast) + ")"),
- new Choice(Constants.choice.compression.bzip2, "BZIP2 ("
- + getString(R.string.compression_very_slow) + ")"),
- };
- ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getActivity(),
- android.R.layout.simple_spinner_item, choices);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mFileCompression.setAdapter(adapter);
-
- int defaultFileCompression = Preferences.getPreferences(getActivity()).getDefaultFileCompression();
- for (int i = 0; i < choices.length; ++i) {
- if (choices[i].getId() == defaultFileCompression) {
- mFileCompression.setSelection(i);
- break;
+ mAddView = inflater.inflate(R.layout.file_list_entry_add, null);
+ mAddView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ addInputUri();
}
- }
-
- mDeleteAfter = (CheckBox) view.findViewById(R.id.deleteAfterEncryption);
- mShareAfter = (CheckBox) view.findViewById(R.id.shareAfterEncryption);
-
- mAsciiArmor = (CheckBox) view.findViewById(R.id.asciiArmor);
- mAsciiArmor.setChecked(Preferences.getPreferences(getActivity()).getDefaultAsciiArmor());
+ });
+ ListView listView = (ListView) view.findViewById(R.id.selected_files_list);
+ listView.addFooterView(mAddView);
+ listView.setAdapter(mAdapter);
return view;
}
@@ -153,267 +106,126 @@ public class EncryptFileFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- String filename = getArguments().getString(ARG_FILENAME);
- if (filename != null) {
- mFilename.setText(filename);
- }
- boolean asciiArmor = getArguments().getBoolean(ARG_ASCII_ARMOR);
- if (asciiArmor) {
- mAsciiArmor.setChecked(asciiArmor);
- }
+ addInputUris(getArguments().<Uri>getParcelableArrayList(ARG_URIS));
}
- /**
- * Guess output filename based on input path
- *
- * @param path
- * @return Suggestion for output filename
- */
- private String guessOutputFilename(String path) {
- // output in the same directory but with additional ending
- File file = new File(path);
- String ending = (mAsciiArmor.isChecked() ? ".asc" : ".gpg");
- String outputFilename = file.getParent() + File.separator + file.getName() + ending;
-
- return outputFilename;
+ private void addInputUri() {
+ if (Constants.KITKAT) {
+ FileHelper.openDocument(EncryptFileFragment.this, "*/*", true, REQUEST_CODE_INPUT);
+ } else {
+ FileHelper.openFile(EncryptFileFragment.this, mEncryptInterface.getInputUris().isEmpty() ?
+ null : mEncryptInterface.getInputUris().get(mEncryptInterface.getInputUris().size() - 1),
+ "*/*", REQUEST_CODE_INPUT);
+ }
}
- private void showOutputFileDialog() {
- // Message is received after file is selected
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == FileDialogFragment.MESSAGE_OKAY) {
- Bundle data = message.getData();
- if (data.containsKey(FileDialogFragment.MESSAGE_DATA_URI)) {
- mOutputUri = data.getParcelable(FileDialogFragment.MESSAGE_DATA_URI);
- } else {
- mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
- }
- encryptStart();
- }
+ private void addInputUris(List<Uri> uris) {
+ if (uris != null) {
+ for (Uri uri : uris) {
+ addInputUri(uri);
}
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- mFileDialog = FileDialogFragment.newInstance(messenger,
- getString(R.string.title_encrypt_to_file),
- getString(R.string.specify_file_to_encrypt_to), mOutputFilename, null);
-
- mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog");
- }
-
- private void encryptClicked() {
- String currentFilename = mFilename.getText().toString();
- if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
- mInputUri = null;
- mInputFilename = mFilename.getText().toString();
- }
-
- if (mInputUri == null) {
- mOutputFilename = guessOutputFilename(mInputFilename);
}
+ }
- if (mInputFilename.equals("")) {
- Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR);
+ private void addInputUri(Uri inputUri) {
+ if (inputUri == null) {
return;
}
- if (mInputUri == null && !mInputFilename.startsWith("content")) {
- File file = new File(mInputFilename);
- if (!file.exists() || !file.isFile()) {
- Notify.showNotify(
- getActivity(),
- getString(R.string.error_message,
- getString(R.string.error_file_not_found)), Notify.Style.ERROR
- );
- return;
- }
- }
-
- if (mEncryptInterface.isModeSymmetric()) {
- // symmetric encryption
+ mEncryptInterface.getInputUris().add(inputUri);
+ mEncryptInterface.notifyUpdate();
- boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
- && mEncryptInterface.getPassphrase().length() != 0);
- if (!gotPassphrase) {
- Notify.showNotify(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
- ;
- return;
- }
+ /**
+ * 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.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
- Notify.showNotify(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR);
- return;
- }
+ if (mEncryptInterface.getInputUris().size() > 1) {
+ mEncryptFile.setVisibility(View.GONE);
} else {
- // asymmetric encryption
-
- boolean gotEncryptionKeys = (mEncryptInterface.getEncryptionKeys() != null
- && mEncryptInterface.getEncryptionKeys().length > 0);
-
- if (!gotEncryptionKeys) {
- Notify.showNotify(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR);
- return;
- }
-
- if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) {
- Notify.showNotify(getActivity(), R.string.select_encryption_or_signature_key,
- Notify.Style.ERROR);
- 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;
- }
+ mEncryptFile.setVisibility(View.VISIBLE);
}
-
- showOutputFileDialog();
}
- private void encryptStart() {
- // 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();
+ private void delInputUri(int position) {
+ mEncryptInterface.getInputUris().remove(position);
+ mEncryptInterface.notifyUpdate();
- Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
- + mOutputFilename + ",mInputUri=" + mInputUri + ", mOutputUri="
- + mOutputUri);
-
- if (mInputUri != null) {
- data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
- data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
+ if (mEncryptInterface.getInputUris().size() > 1) {
+ mEncryptFile.setVisibility(View.GONE);
} else {
- data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_FILE);
- data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
+ mEncryptFile.setVisibility(View.VISIBLE);
}
+ }
- if (mOutputUri != null) {
- data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
- data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
+ private void showOutputFileDialog() {
+ if (mEncryptInterface.getInputUris().size() > 1 || mEncryptInterface.getInputUris().isEmpty()) {
+ throw new IllegalStateException();
+ }
+ Uri inputUri = mEncryptInterface.getInputUris().get(0);
+ if (!Constants.KITKAT) {
+ File file = new File(inputUri.getPath());
+ File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
+ String targetName = FileHelper.getFilename(getActivity(), inputUri) +
+ (mEncryptInterface.isUseArmor() ? ".asc" : ".gpg");
+ File targetFile = new File(parentDir, targetName);
+ FileHelper.saveFile(this, getString(R.string.title_encrypt_to_file),
+ getString(R.string.specify_file_to_encrypt_to), targetFile, REQUEST_CODE_OUTPUT);
} else {
- data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_FILE);
- data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename);
+ FileHelper.saveDocument(this, "*/*", FileHelper.getFilename(getActivity(), inputUri) +
+ (mEncryptInterface.isUseArmor() ? ".asc" : ".gpg"), REQUEST_CODE_OUTPUT);
}
+ }
- if (mEncryptInterface.isModeSymmetric()) {
- Log.d(Constants.TAG, "Symmetric encryption enabled!");
- String passphrase = mEncryptInterface.getPassphrase();
- if (passphrase.length() == 0) {
- passphrase = null;
+ private void encryptClicked(boolean share) {
+ if (share) {
+ mEncryptInterface.getOutputUris().clear();
+ for (Uri uri : mEncryptInterface.getInputUris()) {
+ String targetName = FileHelper.getFilename(getActivity(), uri) +
+ (mEncryptInterface.isUseArmor() ? ".asc" : ".gpg");
+ mEncryptInterface.getOutputUris().add(TemporaryStorageProvider.createFile(getActivity(), targetName));
}
- 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());
+ mEncryptInterface.startEncrypt(true);
+ } else if (mEncryptInterface.getInputUris().size() == 1) {
+ showOutputFileDialog();
}
+ }
- boolean useAsciiArmor = mAsciiArmor.isChecked();
- data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, useAsciiArmor);
-
- 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) {
- Notify.showNotify(getActivity(), R.string.encrypt_sign_successful,
- Notify.Style.INFO);
-
- if (mDeleteAfter.isChecked()) {
- // Create and show dialog to delete original file
- DeleteFileDialogFragment deleteFileDialog;
- if (mInputUri != null) {
- deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
- } else {
- deleteFileDialog = DeleteFileDialogFragment
- .newInstance(mInputFilename);
- }
- deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
- }
-
- if (mShareAfter.isChecked()) {
- // Share encrypted file
- Intent sendFileIntent = new Intent(Intent.ACTION_SEND);
- sendFileIntent.setType("*/*");
- if (mOutputUri != null) {
- sendFileIntent.putExtra(Intent.EXTRA_STREAM, mOutputUri);
- } else {
- sendFileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(mOutputFilename));
- }
- startActivity(Intent.createChooser(sendFileIntent,
- getString(R.string.title_share_file)));
- }
- }
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ public boolean handleClipData(Intent data) {
+ if (data.getClipData() != null && data.getClipData().getItemCount() > 0) {
+ for (int i = 0; i < data.getClipData().getItemCount(); i++) {
+ Uri uri = data.getClipData().getItemAt(i).getUri();
+ if (uri != null) addInputUri(uri);
}
- };
-
- // 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);
+ return true;
+ }
+ return false;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
- case REQUEST_CODE_FILE: {
+ case REQUEST_CODE_INPUT: {
if (resultCode == Activity.RESULT_OK && data != null) {
- if (Constants.KITKAT) {
- mInputUri = data.getData();
- Cursor cursor = getActivity().getContentResolver().query(mInputUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
- if (cursor != null) {
- if (cursor.moveToNext()) {
- mInputFilename = cursor.getString(0);
- mFilename.setText(mInputFilename);
- }
- cursor.close();
- }
- } else {
- try {
- String path = FileHelper.getPath(getActivity(), data.getData());
- Log.d(Constants.TAG, "path=" + path);
-
- mFilename.setText(path);
- } catch (NullPointerException e) {
- Log.e(Constants.TAG, "Nullpointer while retrieving path!");
- }
+ if (!Constants.KITKAT || !handleClipData(data)) {
+ addInputUri(data.getData());
}
}
return;
}
+ case REQUEST_CODE_OUTPUT: {
+ // This happens after output file was selected, so start our operation
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ mEncryptInterface.getOutputUris().clear();
+ mEncryptInterface.getOutputUris().add(data.getData());
+ mEncryptInterface.notifyUpdate();
+ mEncryptInterface.startEncrypt(false);
+ }
+ return;
+ }
default: {
super.onActivityResult(requestCode, resultCode, data);
@@ -422,4 +234,57 @@ public class EncryptFileFragment extends Fragment {
}
}
}
+
+ @Override
+ public void onNotifyUpdate() {
+ mAdapter.notifyDataSetChanged();
+ }
+
+ private class SelectedFilesAdapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return mEncryptInterface.getInputUris().size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mEncryptInterface.getInputUris().get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).hashCode();
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ View view;
+ if (convertView == null) {
+ view = getActivity().getLayoutInflater().inflate(R.layout.file_list_entry, null);
+ } else {
+ view = convertView;
+ }
+ ((TextView) view.findViewById(R.id.filename)).setText(FileHelper.getFilename(getActivity(), mEncryptInterface.getInputUris().get(position)));
+ long size = FileHelper.getFileSize(getActivity(), mEncryptInterface.getInputUris().get(position));
+ if (size == -1) {
+ ((TextView) view.findViewById(R.id.filesize)).setText("");
+ } else {
+ ((TextView) view.findViewById(R.id.filesize)).setText(FileHelper.readableFileSize(size));
+ }
+ view.findViewById(R.id.action_remove_file_from_list).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ delInputUri(position);
+ }
+ });
+ int px = OtherHelper.dpToPx(getActivity(), 48);
+ Bitmap bitmap = FileHelper.getThumbnail(getActivity(), mEncryptInterface.getInputUris().get(position), new Point(px, px));
+ if (bitmap != null) {
+ ((ImageView) view.findViewById(R.id.thumbnail)).setImageBitmap(bitmap);
+ } else {
+ ((ImageView) view.findViewById(R.id.thumbnail)).setImageResource(R.drawable.ic_doc_generic_am);
+ }
+ return view;
+ }
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java
index e1760b4ed..6aae649bd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java
@@ -25,21 +25,29 @@ import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.devspark.appmsg.AppMsg;
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
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.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.Notify;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
public class EncryptMessageFragment extends Fragment {
public static final String ARG_TEXT = "text";
@@ -69,18 +77,34 @@ public class EncryptMessageFragment extends Fragment {
View view = inflater.inflate(R.layout.encrypt_message_fragment, container, false);
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);
mEncryptShare = view.findViewById(R.id.action_encrypt_share);
mEncryptClipboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- encryptClicked(true);
+ mEncryptInterface.startEncrypt(false);
}
});
mEncryptShare.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- encryptClicked(false);
+ mEncryptInterface.startEncrypt(true);
}
});
@@ -92,7 +116,7 @@ public class EncryptMessageFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- String text = getArguments().getString(ARG_TEXT);
+ String text = mEncryptInterface.getMessage();
if (text != null) {
mMessage.setText(text);
}
@@ -117,138 +141,4 @@ public class EncryptMessageFragment extends Fragment {
return message;
}
-
- private void encryptClicked(final boolean toClipboard) {
- if (mEncryptInterface.isModeSymmetric()) {
- // symmetric encryption
-
- boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
- && mEncryptInterface.getPassphrase().length() != 0);
- if (!gotPassphrase) {
- Notify.showNotify(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR);
- return;
- }
-
- if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
- Notify.showNotify(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR);
- return;
- }
-
- } else {
- // asymmetric encryption
-
- boolean gotEncryptionKeys = (mEncryptInterface.getEncryptionKeys() != null
- && mEncryptInterface.getEncryptionKeys().length > 0);
-
- if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) {
- Notify.showNotify(getActivity(), R.string.select_encryption_or_signature_key,
- Notify.Style.ERROR);
- 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);
- Notify.showNotify(getActivity(),
- R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO);
- } 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");
-
- 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);
- }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java
index 8efa07953..86731b162 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java
@@ -29,27 +29,20 @@ import android.widget.EditText;
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 mPassphraseAgain;
- // Container Activity must implement this interface
- public interface OnSymmetricKeySelection {
- public void onPassphraseUpdate(String passphrase);
-
- public void onPassphraseAgainUpdate(String passphrase);
- }
-
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
- mPassphraseUpdateListener = (OnSymmetricKeySelection) activity;
+ mEncryptInterface = (EncryptActivityInterface) activity;
} 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);
mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain);
- mPassphrase.addTextChangedListener(new TextWatcher() {
+ TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@@ -74,25 +67,21 @@ public class EncryptSymmetricFragment extends Fragment {
@Override
public void afterTextChanged(Editable s) {
// update passphrase in EncryptActivity
- mPassphraseUpdateListener.onPassphraseUpdate(s.toString());
- }
- });
- mPassphraseAgain.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ if (mPassphrase.getText().toString().equals(mPassphraseAgain.getText().toString())) {
+ mEncryptInterface.setPassphrase(s.toString());
+ } else {
+ mEncryptInterface.setPassphrase(null);
+ }
}
+ };
+ mPassphrase.addTextChangedListener(textWatcher);
+ mPassphraseAgain.addTextChangedListener(textWatcher);
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
+ return view;
+ }
- @Override
- public void afterTextChanged(Editable s) {
- // update passphrase in EncryptActivity
- mPassphraseUpdateListener.onPassphraseAgainUpdate(s.toString());
- }
- });
+ @Override
+ public void onNotifyUpdate() {
- return view;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
index ce885c419..cb53647f6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
@@ -66,7 +66,7 @@ public class ImportKeysFileFragment extends Fragment {
// open .asc or .gpg files
// setting it to text/plain prevents Cyanogenmod's file manager from selecting asc
// or gpg types!
- FileHelper.openFile(ImportKeysFileFragment.this, Constants.Path.APP_DIR + "/",
+ FileHelper.openFile(ImportKeysFileFragment.this, Uri.fromFile(Constants.Path.APP_DIR),
"*/*", REQUEST_CODE_FILE);
}
});
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index b0caaa10c..b8efa6d86 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -176,8 +176,8 @@ public class KeyListFragment extends LoaderFragment
case R.id.menu_key_list_multi_export: {
ids = mAdapter.getCurrentSelectedMasterKeyIds();
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
- mExportHelper.showExportKeysDialog(
- ids, Constants.Path.APP_DIR_FILE, mAdapter.isAnySecretSelected());
+ mExportHelper.showExportKeysDialog(ids, Constants.Path.APP_DIR_FILE,
+ mAdapter.isAnySecretSelected());
break;
}
case R.id.menu_key_list_multi_select_all: {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 03e446723..69efb4cbd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -317,8 +317,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
exportHelper.showExportKeysDialog(
new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
- Constants.Path.APP_DIR_FILE,
- ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) == 1)
+ Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) == 1)
);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java
index cae6cf043..27ce4faee 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java
@@ -18,43 +18,24 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.DialogInterface;
-import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
import android.provider.DocumentsContract;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
-import android.widget.Toast;
+import android.widget.Toast;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.helper.FileHelper;
public class DeleteFileDialogFragment extends DialogFragment {
- private static final String ARG_DELETE_FILE = "delete_file";
private static final String ARG_DELETE_URI = "delete_uri";
/**
* Creates new instance of this delete file dialog fragment
*/
- public static DeleteFileDialogFragment newInstance(String deleteFile) {
- DeleteFileDialogFragment frag = new DeleteFileDialogFragment();
- Bundle args = new Bundle();
-
- args.putString(ARG_DELETE_FILE, deleteFile);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Creates new instance of this delete file dialog fragment
- */
public static DeleteFileDialogFragment newInstance(Uri deleteUri) {
DeleteFileDialogFragment frag = new DeleteFileDialogFragment();
Bundle args = new Bundle();
@@ -73,15 +54,15 @@ public class DeleteFileDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
- final Uri deleteUri = getArguments().containsKey(ARG_DELETE_URI) ? getArguments().<Uri>getParcelable(ARG_DELETE_URI) : null;
- final String deleteFile = getArguments().getString(ARG_DELETE_FILE);
+ final Uri deleteUri = getArguments().getParcelable(ARG_DELETE_URI);
+ final String deleteFilename = FileHelper.getFilename(getActivity(), deleteUri);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
alert.setTitle(R.string.warning);
- alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile));
+ alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFilename));
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -89,51 +70,23 @@ public class DeleteFileDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int id) {
dismiss();
- if (deleteUri != null) {
- // We can not securely delete Documents, so just use usual delete on them
- DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri);
- return;
- }
-
- // Send all information needed to service to edit key in other thread
- Intent intent = new Intent(activity, KeychainIntentService.class);
-
- // fill values for this action
- Bundle data = new Bundle();
-
- intent.setAction(KeychainIntentService.ACTION_DELETE_FILE_SECURELY);
- data.putString(KeychainIntentService.DELETE_FILE, deleteFile);
- intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
- getString(R.string.progress_deleting_securely),
- ProgressDialog.STYLE_HORIZONTAL,
- false,
- null);
-
- // Message is received after deleting is done in KeychainIntentService
- KeychainIntentServiceHandler saveHandler =
- new KeychainIntentServiceHandler(activity, deletingDialog) {
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentHandler first
- super.handleMessage(message);
-
- if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Toast.makeText(activity, R.string.file_delete_successful,
- Toast.LENGTH_SHORT).show();
- }
+ // We can not securely delete Uris, so just use usual delete on them
+ if (Constants.KITKAT) {
+ if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
+ Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
+ return;
}
- };
+ }
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+ if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
+ Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
+ return;
+ }
- // show progress dialog
- deletingDialog.show(activity.getSupportFragmentManager(), "deletingDialog");
+ Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed, deleteFilename), Toast.LENGTH_SHORT).show();
- // start service with intent
- activity.startService(intent);
+ // TODO: We can't delete that file...
+ // If possible we should find out if deletion is possible before even showing the option to do so.
}
});
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
index 448787ee2..80341aeaa 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
@@ -23,13 +23,11 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.provider.OpenableColumns;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
@@ -37,12 +35,17 @@ import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
-
+import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.File;
+
+/**
+ * This is a file chooser dialog no longer used with KitKat
+ */
public class FileDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger";
private static final String ARG_TITLE = "title";
@@ -52,8 +55,7 @@ public class FileDialogFragment extends DialogFragment {
public static final int MESSAGE_OKAY = 1;
- public static final String MESSAGE_DATA_URI = "uri";
- public static final String MESSAGE_DATA_FILENAME = "filename";
+ public static final String MESSAGE_DATA_FILE = "file";
public static final String MESSAGE_DATA_CHECKED = "checked";
private Messenger mMessenger;
@@ -63,8 +65,7 @@ public class FileDialogFragment extends DialogFragment {
private CheckBox mCheckBox;
private TextView mMessageTextView;
- private String mOutputFilename;
- private Uri mOutputUri;
+ private File mFile;
private static final int REQUEST_CODE = 0x00007004;
@@ -72,14 +73,14 @@ public class FileDialogFragment extends DialogFragment {
* Creates new instance of this file dialog fragment
*/
public static FileDialogFragment newInstance(Messenger messenger, String title, String message,
- String defaultFile, String checkboxText) {
+ File defaultFile, String checkboxText) {
FileDialogFragment frag = new FileDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger);
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
- args.putString(ARG_DEFAULT_FILE, defaultFile);
+ args.putString(ARG_DEFAULT_FILE, defaultFile.getAbsolutePath());
args.putString(ARG_CHECKBOX_TEXT, checkboxText);
frag.setArguments(args);
@@ -98,7 +99,11 @@ public class FileDialogFragment extends DialogFragment {
String title = getArguments().getString(ARG_TITLE);
String message = getArguments().getString(ARG_MESSAGE);
- mOutputFilename = getArguments().getString(ARG_DEFAULT_FILE);
+ mFile = new File(getArguments().getString(ARG_DEFAULT_FILE));
+ if (!mFile.isAbsolute()) {
+ // We use OK dir by default
+ mFile = new File(Constants.Path.APP_DIR.getAbsolutePath(), mFile.getName());
+ }
String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT);
LayoutInflater inflater = (LayoutInflater) activity
@@ -112,18 +117,14 @@ public class FileDialogFragment extends DialogFragment {
mMessageTextView.setText(message);
mFilename = (EditText) view.findViewById(R.id.input);
- mFilename.setText(mOutputFilename);
+ mFilename.setText(mFile.getName());
mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// only .asc or .gpg files
// setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
// or gpg types!
- if (Constants.KITKAT) {
- FileHelper.saveDocument(FileDialogFragment.this, mOutputUri, "*/*", REQUEST_CODE);
- } else {
- FileHelper.openFile(FileDialogFragment.this, mOutputFilename, "*/*", REQUEST_CODE);
- }
+ FileHelper.openFile(FileDialogFragment.this, Uri.fromFile(mFile), "*/*", REQUEST_CODE);
}
});
@@ -146,19 +147,23 @@ public class FileDialogFragment extends DialogFragment {
dismiss();
String currentFilename = mFilename.getText().toString();
- if (mOutputFilename == null || !mOutputFilename.equals(currentFilename)) {
- mOutputUri = null;
- mOutputFilename = mFilename.getText().toString();
+ if (currentFilename == null || currentFilename.isEmpty()) {
+ // No file is like pressing cancel, UI: maybe disable positive button in this case?
+ return;
+ }
+
+ if (mFile == null || currentFilename.startsWith("/")) {
+ mFile = new File(currentFilename);
+ } else if (!mFile.getName().equals(currentFilename)) {
+ // We update our File object if user changed name!
+ mFile = new File(mFile.getParentFile(), currentFilename);
}
boolean checked = mCheckBox.isEnabled() && mCheckBox.isChecked();
// return resulting data back to activity
Bundle data = new Bundle();
- if (mOutputUri != null) {
- data.putParcelable(MESSAGE_DATA_URI, mOutputUri);
- }
- data.putString(MESSAGE_DATA_FILENAME, mFilename.getText().toString());
+ data.putString(MESSAGE_DATA_FILE, mFile.getAbsolutePath());
data.putBoolean(MESSAGE_DATA_CHECKED, checked);
sendMessageToHandler(MESSAGE_OKAY, data);
@@ -175,44 +180,17 @@ public class FileDialogFragment extends DialogFragment {
return alert.show();
}
- /**
- * Updates filename in dialog, normally called in onActivityResult in activity using the
- * FileDialog
- */
- private void setFilename(String filename) {
- AlertDialog dialog = (AlertDialog) getDialog();
- EditText filenameEditText = (EditText) dialog.findViewById(R.id.input);
-
- if (filenameEditText != null) {
- filenameEditText.setText(filename);
- }
- }
-
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) {
case REQUEST_CODE: {
if (resultCode == Activity.RESULT_OK && data != null) {
- if (Constants.KITKAT) {
- mOutputUri = data.getData();
- Cursor cursor = getActivity().getContentResolver().query(mOutputUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
- if (cursor != null) {
- if (cursor.moveToNext()) {
- mOutputFilename = cursor.getString(0);
- mFilename.setText(mOutputFilename);
- }
- cursor.close();
- }
+ File file = new File(data.getData().getPath());
+ if (file.getParentFile().exists()) {
+ mFile = file;
+ mFilename.setText(mFile.getName());
} else {
- try {
- String path = data.getData().getPath();
- Log.d(Constants.TAG, "path=" + path);
-
- // set filename used in export/import dialogs
- setFilename(path);
- } catch (NullPointerException e) {
- Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
- }
+ AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
new file mode 100644
index 000000000..7bdaf27c7
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
@@ -0,0 +1,232 @@
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.app.Activity;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.tokenautocomplete.FilteredArrayAdapter;
+import com.tokenautocomplete.TokenCompleteTextView;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class EncryptKeyCompletionView extends TokenCompleteTextView {
+ public EncryptKeyCompletionView(Context context) {
+ super(context);
+ initView();
+ }
+
+ public EncryptKeyCompletionView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initView();
+ }
+
+ public EncryptKeyCompletionView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initView();
+ }
+
+ private void initView() {
+ swapCursor(null);
+ setPrefix(getContext().getString(R.string.label_to) + ": ");
+ allowDuplicates(false);
+ }
+
+ @Override
+ protected View getViewForObject(Object object) {
+ if (object instanceof EncryptionKey) {
+ LayoutInflater l = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+ View view = l.inflate(R.layout.recipient_box_entry, null);
+ ((TextView) view.findViewById(android.R.id.text1)).setText(((EncryptionKey) object).getPrimary());
+ setImageByKey((ImageView) view.findViewById(android.R.id.icon), (EncryptionKey) object);
+ return view;
+ }
+ return null;
+ }
+
+ private void setImageByKey(ImageView view, EncryptionKey key) {
+ Bitmap photo = ContactHelper.photoFromFingerprint(getContext().getContentResolver(), key.getFingerprint());
+
+ if (photo != null) {
+ view.setImageBitmap(photo);
+ } else {
+ view.setImageResource(R.drawable.ic_generic_man);
+ }
+ }
+
+ @Override
+ protected Object defaultObject(String completionText) {
+ // TODO: We could try to automagically download the key if it's unknown but a key id
+ /*if (completionText.startsWith("0x")) {
+
+ }*/
+ return null;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (getContext() instanceof FragmentActivity) {
+ ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ return new CursorLoader(getContext(), KeychainContract.KeyRings.buildUnifiedKeyRingsUri(),
+ new String[]{KeychainContract.KeyRings.HAS_ENCRYPT, KeychainContract.KeyRings.KEY_ID, KeychainContract.KeyRings.USER_ID, KeychainContract.KeyRings.FINGERPRINT},
+ null, null, null);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ swapCursor(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ swapCursor(null);
+ }
+ });
+ }
+ }
+
+ public void swapCursor(Cursor cursor) {
+ if (cursor == null) {
+ setAdapter(new EncryptKeyAdapter(Collections.<EncryptionKey>emptyList()));
+ return;
+ }
+ ArrayList<EncryptionKey> keys = new ArrayList<EncryptionKey>();
+ cursor.moveToFirst();
+ while (cursor.moveToNext()) {
+ try {
+ if (cursor.getInt(cursor.getColumnIndexOrThrow(KeychainContract.KeyRings.HAS_ENCRYPT)) != 0) {
+ EncryptionKey key = new EncryptionKey(cursor);
+ keys.add(key);
+ }
+ } catch (Exception e) {
+ Log.w(Constants.TAG, e);
+ return;
+ }
+ }
+ setAdapter(new EncryptKeyAdapter(keys));
+ }
+
+ public class EncryptionKey {
+ private String mUserId;
+ private long mKeyId;
+ private String mFingerprint;
+
+ public EncryptionKey(String userId, long keyId, String fingerprint) {
+ this.mUserId = userId;
+ this.mKeyId = keyId;
+ this.mFingerprint = fingerprint;
+ }
+
+ public EncryptionKey(Cursor cursor) {
+ this(cursor.getString(cursor.getColumnIndexOrThrow(KeychainContract.KeyRings.USER_ID)),
+ cursor.getLong(cursor.getColumnIndexOrThrow(KeychainContract.KeyRings.KEY_ID)),
+ PgpKeyHelper.convertFingerprintToHex(
+ cursor.getBlob(cursor.getColumnIndexOrThrow(KeychainContract.KeyRings.FINGERPRINT))));
+
+ }
+
+ public EncryptionKey(CachedPublicKeyRing ring) throws PgpGeneralException {
+ this(ring.getPrimaryUserId(), ring.extractOrGetMasterKeyId(),
+ PgpKeyHelper.convertFingerprintToHex(ring.getFingerprint()));
+ }
+
+ public String getUserId() {
+ return mUserId;
+ }
+
+ public String getFingerprint() {
+ return mFingerprint;
+ }
+
+ public String getPrimary() {
+ String[] userId = KeyRing.splitUserId(mUserId);
+ if (userId[0] != null && userId[2] != null) {
+ return userId[0] + " (" + userId[2] + ")";
+ } else if (userId[0] != null) {
+ return userId[0];
+ } else {
+ return userId[1];
+ }
+ }
+
+ public String getSecondary() {
+ String[] userId = KeyRing.splitUserId(mUserId);
+ if (userId[0] != null) {
+ return userId[1] + " (" + getKeyIdHexShort() + ")";
+ } else {
+ return getKeyIdHex();
+ }
+ }
+
+ public long getKeyId() {
+ return mKeyId;
+ }
+
+ public String getKeyIdHex() {
+ return PgpKeyHelper.convertKeyIdToHex(mKeyId);
+ }
+
+ public String getKeyIdHexShort() {
+ return PgpKeyHelper.convertKeyIdToHexShort(mKeyId);
+ }
+
+ @Override
+ public String toString() {
+ return Long.toString(mKeyId);
+ }
+ }
+
+ private class EncryptKeyAdapter extends FilteredArrayAdapter<EncryptionKey> {
+
+ public EncryptKeyAdapter(List<EncryptionKey> objs) {
+ super(EncryptKeyCompletionView.this.getContext(), 0, 0, objs);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ LayoutInflater l = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+ View view;
+ if (convertView != null) {
+ view = convertView;
+ } else {
+ view = l.inflate(R.layout.recipient_selection_list_entry, null);
+ }
+ ((TextView) view.findViewById(android.R.id.title)).setText(getItem(position).getPrimary());
+ ((TextView) view.findViewById(android.R.id.text1)).setText(getItem(position).getSecondary());
+ setImageByKey((ImageView) view.findViewById(android.R.id.icon), getItem(position));
+ return view;
+ }
+
+ @Override
+ protected boolean keepObject(EncryptionKey obj, String mask) {
+ String m = mask.toLowerCase();
+ return obj.getUserId().toLowerCase().contains(m) ||
+ obj.getKeyIdHex().contains(m) ||
+ obj.getKeyIdHexShort().startsWith(m);
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
new file mode 100644
index 000000000..516e5ec39
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
@@ -0,0 +1,45 @@
+package org.sufficientlysecure.keychain.ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class NoSwipeWrapContentViewPager extends android.support.v4.view.ViewPager {
+ public NoSwipeWrapContentViewPager(Context context) {
+ super(context);
+ }
+
+ public NoSwipeWrapContentViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+ int height;
+ View child = getChildAt(getCurrentItem());
+ if (child != null) {
+ child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ height = child.getMeasuredHeight();
+ } else {
+ height = 0;
+ }
+
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent arg0) {
+ // Never allow swiping to switch between pages
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // Never allow swiping to switch between pages
+ return false;
+ }
+}