mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-08-13 15:53:53 -04:00
Merge pull request #664 from mar-v-in/improve-file
Add Document/Storage API support
This commit is contained in:
commit
313e571a61
@ -17,6 +17,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
|
||||
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
||||
@ -48,6 +49,8 @@ public final class Constants {
|
||||
|
||||
public static final String CUSTOM_CONTACT_DATA_MIME_TYPE = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key";
|
||||
|
||||
public static boolean KITKAT = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
|
||||
public static final class Path {
|
||||
public static final String APP_DIR = Environment.getExternalStorageDirectory()
|
||||
+ "/OpenKeychain";
|
||||
|
@ -17,12 +17,14 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.helper;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.widget.Toast;
|
||||
@ -82,6 +84,39 @@ public class FileHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens the storage browser on Android 4.4 or later for opening a file
|
||||
* @param fragment
|
||||
* @param last default selected file
|
||||
* @param mimeType can be text/plain for example
|
||||
* @param requestCode used to identify the result coming back from storage browser onActivityResult() in your
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public static void openDocument(Fragment fragment, Uri last, String mimeType, int requestCode) {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setData(last);
|
||||
intent.setType(mimeType);
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the storage browser on Android 4.4 or later for saving a file
|
||||
* @param fragment
|
||||
* @param last default selected file
|
||||
* @param mimeType can be text/plain for example
|
||||
* @param requestCode used to identify the result coming back from storage browser onActivityResult() in your
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public static void saveDocument(Fragment fragment, Uri last, String mimeType, int requestCode) {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setData(last);
|
||||
intent.setType(mimeType);
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
private static Intent buildFileIntent(String filename, String mimeType) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
@ -104,9 +104,11 @@ public class KeychainIntentService extends IntentService
|
||||
|
||||
// encrypt, decrypt, import export
|
||||
public static final String TARGET = "target";
|
||||
public static final String SOURCE = "source";
|
||||
// possible targets:
|
||||
public static final int TARGET_BYTES = 1;
|
||||
public static final int TARGET_URI = 2;
|
||||
public static final int IO_BYTES = 1;
|
||||
public static final int IO_FILE = 2; // This was misleadingly TARGET_URI before!
|
||||
public static final int IO_URI = 3;
|
||||
|
||||
// encrypt
|
||||
public static final String ENCRYPT_SIGNATURE_KEY_ID = "secret_key_id";
|
||||
@ -115,7 +117,9 @@ public class KeychainIntentService extends IntentService
|
||||
public static final String ENCRYPT_COMPRESSION_ID = "compression_id";
|
||||
public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes";
|
||||
public static final String ENCRYPT_INPUT_FILE = "input_file";
|
||||
public static final String ENCRYPT_INPUT_URI = "input_uri";
|
||||
public static final String ENCRYPT_OUTPUT_FILE = "output_file";
|
||||
public static final String ENCRYPT_OUTPUT_URI = "output_uri";
|
||||
public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase";
|
||||
|
||||
// decrypt/verify
|
||||
@ -214,7 +218,7 @@ public class KeychainIntentService extends IntentService
|
||||
if (ACTION_ENCRYPT_SIGN.equals(action)) {
|
||||
try {
|
||||
/* Input */
|
||||
int target = data.getInt(TARGET);
|
||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||
|
||||
long signatureKeyId = data.getLong(ENCRYPT_SIGNATURE_KEY_ID);
|
||||
String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);
|
||||
@ -222,71 +226,8 @@ public class KeychainIntentService extends IntentService
|
||||
boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR);
|
||||
long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS);
|
||||
int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID);
|
||||
InputStream inStream;
|
||||
long inLength;
|
||||
InputData inputData;
|
||||
OutputStream outStream;
|
||||
// String streamFilename = null;
|
||||
switch (target) {
|
||||
case TARGET_BYTES: /* encrypting bytes directly */
|
||||
byte[] bytes = data.getByteArray(ENCRYPT_MESSAGE_BYTES);
|
||||
|
||||
inStream = new ByteArrayInputStream(bytes);
|
||||
inLength = bytes.length;
|
||||
|
||||
inputData = new InputData(inStream, inLength);
|
||||
outStream = new ByteArrayOutputStream();
|
||||
|
||||
break;
|
||||
case TARGET_URI: /* encrypting file */
|
||||
String inputFile = data.getString(ENCRYPT_INPUT_FILE);
|
||||
String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);
|
||||
|
||||
// check if storage is ready
|
||||
if (!FileHelper.isStorageMounted(inputFile)
|
||||
|| !FileHelper.isStorageMounted(outputFile)) {
|
||||
throw new PgpGeneralException(
|
||||
getString(R.string.error_external_storage_not_ready));
|
||||
}
|
||||
|
||||
inStream = new FileInputStream(inputFile);
|
||||
File file = new File(inputFile);
|
||||
inLength = file.length();
|
||||
inputData = new InputData(inStream, inLength);
|
||||
|
||||
outStream = new FileOutputStream(outputFile);
|
||||
|
||||
break;
|
||||
|
||||
// TODO: not used currently
|
||||
// case TARGET_STREAM: /* Encrypting stream from content uri */
|
||||
// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI);
|
||||
//
|
||||
// // InputStream
|
||||
// InputStream in = getContentResolver().openInputStream(providerUri);
|
||||
// inLength = PgpHelper.getLengthOfStream(in);
|
||||
// inputData = new InputData(in, inLength);
|
||||
//
|
||||
// // OutputStream
|
||||
// try {
|
||||
// while (true) {
|
||||
// streamFilename = PgpHelper.generateRandomFilename(32);
|
||||
// if (streamFilename == null) {
|
||||
// throw new PgpGeneralException("couldn't generate random file name");
|
||||
// }
|
||||
// openFileInput(streamFilename).close();
|
||||
// }
|
||||
// } catch (FileNotFoundException e) {
|
||||
// // found a name that isn't used yet
|
||||
// }
|
||||
// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
|
||||
//
|
||||
// break;
|
||||
|
||||
default:
|
||||
throw new PgpGeneralException("No target choosen!");
|
||||
|
||||
}
|
||||
InputData inputData = createEncryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
|
||||
/* Operation */
|
||||
PgpSignEncrypt.Builder builder =
|
||||
@ -311,7 +252,7 @@ public class KeychainIntentService extends IntentService
|
||||
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId));
|
||||
|
||||
// this assumes that the bytes are cleartext (valid for current implementation!)
|
||||
if (target == TARGET_BYTES) {
|
||||
if (source == IO_BYTES) {
|
||||
builder.setCleartextInput(true);
|
||||
}
|
||||
|
||||
@ -322,24 +263,7 @@ public class KeychainIntentService extends IntentService
|
||||
/* Output */
|
||||
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
switch (target) {
|
||||
case TARGET_BYTES:
|
||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
||||
|
||||
resultData.putByteArray(RESULT_BYTES, output);
|
||||
|
||||
break;
|
||||
case TARGET_URI:
|
||||
// nothing, file was written, just send okay
|
||||
|
||||
break;
|
||||
// case TARGET_STREAM:
|
||||
// String uri = DataStream.buildDataStreamUri(streamFilename).toString();
|
||||
// resultData.putString(RESULT_URI, uri);
|
||||
//
|
||||
// break;
|
||||
}
|
||||
finalizeEncryptOutputStream(data, resultData, outStream);
|
||||
|
||||
OtherHelper.logDebugBundle(resultData, "resultData");
|
||||
|
||||
@ -350,78 +274,10 @@ public class KeychainIntentService extends IntentService
|
||||
} else if (ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||
try {
|
||||
/* Input */
|
||||
int target = data.getInt(TARGET);
|
||||
|
||||
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
|
||||
InputStream inStream;
|
||||
long inLength;
|
||||
InputData inputData;
|
||||
OutputStream outStream;
|
||||
String streamFilename = null;
|
||||
switch (target) {
|
||||
case TARGET_BYTES: /* decrypting bytes directly */
|
||||
inStream = new ByteArrayInputStream(bytes);
|
||||
inLength = bytes.length;
|
||||
|
||||
inputData = new InputData(inStream, inLength);
|
||||
outStream = new ByteArrayOutputStream();
|
||||
|
||||
break;
|
||||
|
||||
case TARGET_URI: /* decrypting file */
|
||||
String inputFile = data.getString(ENCRYPT_INPUT_FILE);
|
||||
String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);
|
||||
|
||||
// check if storage is ready
|
||||
if (!FileHelper.isStorageMounted(inputFile)
|
||||
|| !FileHelper.isStorageMounted(outputFile)) {
|
||||
throw new PgpGeneralException(
|
||||
getString(R.string.error_external_storage_not_ready));
|
||||
}
|
||||
|
||||
// InputStream
|
||||
inLength = -1;
|
||||
inStream = new FileInputStream(inputFile);
|
||||
File file = new File(inputFile);
|
||||
inLength = file.length();
|
||||
inputData = new InputData(inStream, inLength);
|
||||
|
||||
// OutputStream
|
||||
outStream = new FileOutputStream(outputFile);
|
||||
|
||||
break;
|
||||
|
||||
// TODO: not used, maybe contains code useful for new decrypt method for files?
|
||||
// case TARGET_STREAM: /* decrypting stream from content uri */
|
||||
// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI);
|
||||
//
|
||||
// // InputStream
|
||||
// InputStream in = getContentResolver().openInputStream(providerUri);
|
||||
// inLength = PgpHelper.getLengthOfStream(in);
|
||||
// inputData = new InputData(in, inLength);
|
||||
//
|
||||
// // OutputStream
|
||||
// try {
|
||||
// while (true) {
|
||||
// streamFilename = PgpHelper.generateRandomFilename(32);
|
||||
// if (streamFilename == null) {
|
||||
// throw new PgpGeneralException("couldn't generate random file name");
|
||||
// }
|
||||
// openFileInput(streamFilename).close();
|
||||
// }
|
||||
// } catch (FileNotFoundException e) {
|
||||
// // found a name that isn't used yet
|
||||
// }
|
||||
// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
|
||||
//
|
||||
// break;
|
||||
|
||||
default:
|
||||
throw new PgpGeneralException("No target choosen!");
|
||||
|
||||
}
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
|
||||
/* Operation */
|
||||
|
||||
@ -452,21 +308,7 @@ public class KeychainIntentService extends IntentService
|
||||
|
||||
/* Output */
|
||||
|
||||
switch (target) {
|
||||
case TARGET_BYTES:
|
||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
||||
resultData.putByteArray(RESULT_DECRYPTED_BYTES, output);
|
||||
break;
|
||||
case TARGET_URI:
|
||||
// nothing, file was written, just send okay and verification bundle
|
||||
|
||||
break;
|
||||
// case TARGET_STREAM:
|
||||
// String uri = DataStream.buildDataStreamUri(streamFilename).toString();
|
||||
// resultData.putString(RESULT_URI, uri);
|
||||
//
|
||||
// break;
|
||||
}
|
||||
finalizeDecryptOutputStream(data, resultData, outStream);
|
||||
|
||||
OtherHelper.logDebugBundle(resultData, "resultData");
|
||||
|
||||
@ -805,4 +647,95 @@ public class KeychainIntentService extends IntentService
|
||||
public boolean hasServiceStopped() {
|
||||
return mIsCanceled;
|
||||
}
|
||||
|
||||
private InputData createDecryptInputData(Bundle data) throws IOException, PgpGeneralException {
|
||||
return createCryptInputData(data, DECRYPT_CIPHERTEXT_BYTES);
|
||||
}
|
||||
|
||||
private InputData createEncryptInputData(Bundle data) throws IOException, PgpGeneralException {
|
||||
return createCryptInputData(data, ENCRYPT_MESSAGE_BYTES);
|
||||
}
|
||||
|
||||
private InputData createCryptInputData(Bundle data, String bytesName) throws PgpGeneralException, IOException {
|
||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||
switch (source) {
|
||||
case IO_BYTES: /* encrypting bytes directly */
|
||||
byte[] bytes = data.getByteArray(bytesName);
|
||||
return new InputData(new ByteArrayInputStream(bytes), bytes.length);
|
||||
|
||||
case IO_FILE: /* encrypting file */
|
||||
String inputFile = data.getString(ENCRYPT_INPUT_FILE);
|
||||
|
||||
// check if storage is ready
|
||||
if (!FileHelper.isStorageMounted(inputFile)) {
|
||||
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
||||
}
|
||||
|
||||
return new InputData(new FileInputStream(inputFile), new File(inputFile).length());
|
||||
|
||||
case IO_URI: /* encrypting content uri */
|
||||
Uri providerUri = data.getParcelable(ENCRYPT_INPUT_URI);
|
||||
|
||||
// InputStream
|
||||
InputStream in = getContentResolver().openInputStream(providerUri);
|
||||
return new InputData(in, 0);
|
||||
|
||||
default:
|
||||
throw new PgpGeneralException("No target choosen!");
|
||||
}
|
||||
}
|
||||
|
||||
private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException {
|
||||
int target = data.getInt(TARGET);
|
||||
switch (target) {
|
||||
case IO_BYTES:
|
||||
return new ByteArrayOutputStream();
|
||||
|
||||
case IO_FILE:
|
||||
String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);
|
||||
|
||||
// check if storage is ready
|
||||
if (!FileHelper.isStorageMounted(outputFile)) {
|
||||
throw new PgpGeneralException(
|
||||
getString(R.string.error_external_storage_not_ready));
|
||||
}
|
||||
|
||||
// OutputStream
|
||||
return new FileOutputStream(outputFile);
|
||||
|
||||
case IO_URI:
|
||||
Uri providerUri = data.getParcelable(ENCRYPT_OUTPUT_URI);
|
||||
|
||||
return getContentResolver().openOutputStream(providerUri);
|
||||
|
||||
default:
|
||||
throw new PgpGeneralException("No target choosen!");
|
||||
}
|
||||
}
|
||||
|
||||
private void finalizeEncryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) {
|
||||
finalizeCryptOutputStream(data, resultData, outStream, RESULT_BYTES);
|
||||
}
|
||||
|
||||
private void finalizeDecryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) {
|
||||
finalizeCryptOutputStream(data, resultData, outStream, RESULT_DECRYPTED_BYTES);
|
||||
}
|
||||
|
||||
private void finalizeCryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream, String bytesName) {
|
||||
int target = data.getInt(TARGET);
|
||||
switch (target) {
|
||||
case IO_BYTES:
|
||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
||||
resultData.putByteArray(bytesName, output);
|
||||
break;
|
||||
case IO_FILE:
|
||||
// nothing, file was written, just send okay and verification bundle
|
||||
|
||||
break;
|
||||
case IO_URI:
|
||||
// nothing, output was written, just send okay and verification bundle
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,13 @@ 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;
|
||||
@ -58,7 +61,9 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
private View mDecryptButton;
|
||||
|
||||
private String mInputFilename = null;
|
||||
private Uri mInputUri = null;
|
||||
private String mOutputFilename = null;
|
||||
private Uri mOutputUri = null;
|
||||
|
||||
private FileDialogFragment mFileDialog;
|
||||
|
||||
@ -75,9 +80,13 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (Constants.KITKAT) {
|
||||
FileHelper.openDocument(DecryptFileFragment.this, mInputUri, "*/*", RESULT_CODE_FILE);
|
||||
} else {
|
||||
FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||
RESULT_CODE_FILE);
|
||||
}
|
||||
}
|
||||
});
|
||||
mDecryptButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
@ -99,20 +108,24 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void guessOutputFilename() {
|
||||
mInputFilename = mFilename.getText().toString();
|
||||
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);
|
||||
}
|
||||
mOutputFilename = Constants.Path.APP_DIR + "/" + filename;
|
||||
return Constants.Path.APP_DIR + "/" + filename;
|
||||
}
|
||||
|
||||
private void decryptAction() {
|
||||
String currentFilename = mFilename.getText().toString();
|
||||
if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
|
||||
guessOutputFilename();
|
||||
mInputUri = null;
|
||||
mInputFilename = mFilename.getText().toString();
|
||||
}
|
||||
|
||||
if (mInputUri == null) {
|
||||
mOutputFilename = guessOutputFilename();
|
||||
}
|
||||
|
||||
if (mInputFilename.equals("")) {
|
||||
@ -121,7 +134,7 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInputFilename.startsWith("file")) {
|
||||
if (mInputUri == null && mInputFilename.startsWith("file")) {
|
||||
File file = new File(mInputFilename);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
AppMsg.makeText(
|
||||
@ -143,7 +156,11 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -172,13 +189,25 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
// data
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI);
|
||||
|
||||
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||
+ mOutputFilename);
|
||||
+ mOutputFilename + ",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);
|
||||
}
|
||||
|
||||
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.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
|
||||
|
||||
@ -209,8 +238,13 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
|
||||
if (mDeleteAfter.isChecked()) {
|
||||
// Create and show dialog to delete original file
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
||||
DeleteFileDialogFragment deleteFileDialog;
|
||||
if (mInputUri != null) {
|
||||
deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
|
||||
} else {
|
||||
deleteFileDialog = DeleteFileDialogFragment
|
||||
.newInstance(mInputFilename);
|
||||
}
|
||||
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||
}
|
||||
}
|
||||
@ -234,6 +268,17 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
switch (requestCode) {
|
||||
case RESULT_CODE_FILE: {
|
||||
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);
|
||||
@ -243,6 +288,7 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
Log.e(Constants.TAG, "Nullpointer while retrieving path!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
// data
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
|
||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
|
||||
|
||||
|
@ -20,11 +20,13 @@ 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.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -73,7 +75,9 @@ public class EncryptFileFragment extends Fragment {
|
||||
|
||||
// model
|
||||
private String mInputFilename = null;
|
||||
private Uri mInputUri = null;
|
||||
private String mOutputFilename = null;
|
||||
private Uri mOutputUri = null;
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
@ -104,9 +108,13 @@ public class EncryptFileFragment extends Fragment {
|
||||
mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (Constants.KITKAT) {
|
||||
FileHelper.openDocument(EncryptFileFragment.this, mInputUri, "*/*", RESULT_CODE_FILE);
|
||||
} else {
|
||||
FileHelper.openFile(EncryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||
RESULT_CODE_FILE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mFileCompression = (Spinner) view.findViewById(R.id.fileCompression);
|
||||
@ -178,7 +186,11 @@ public class EncryptFileFragment extends Fragment {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -197,17 +209,20 @@ public class EncryptFileFragment extends Fragment {
|
||||
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("")) {
|
||||
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mInputFilename.startsWith("content")) {
|
||||
if (mInputUri == null && !mInputFilename.startsWith("content")) {
|
||||
File file = new File(mInputFilename);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
AppMsg.makeText(
|
||||
@ -280,7 +295,25 @@ public class EncryptFileFragment extends Fragment {
|
||||
// fill values for this action
|
||||
Bundle data = new Bundle();
|
||||
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI);
|
||||
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);
|
||||
} else {
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_FILE);
|
||||
data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (mEncryptInterface.isModeSymmetric()) {
|
||||
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||
@ -296,12 +329,6 @@ public class EncryptFileFragment extends Fragment {
|
||||
mEncryptInterface.getEncryptionKeys());
|
||||
}
|
||||
|
||||
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||
+ mOutputFilename);
|
||||
|
||||
data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
|
||||
data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename);
|
||||
|
||||
boolean useAsciiArmor = mAsciiArmor.isChecked();
|
||||
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, useAsciiArmor);
|
||||
|
||||
@ -323,8 +350,13 @@ public class EncryptFileFragment extends Fragment {
|
||||
|
||||
if (mDeleteAfter.isChecked()) {
|
||||
// Create and show dialog to delete original file
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
||||
DeleteFileDialogFragment deleteFileDialog;
|
||||
if (mInputUri != null) {
|
||||
deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
|
||||
} else {
|
||||
deleteFileDialog = DeleteFileDialogFragment
|
||||
.newInstance(mInputFilename);
|
||||
}
|
||||
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||
}
|
||||
|
||||
@ -332,7 +364,11 @@ public class EncryptFileFragment extends Fragment {
|
||||
// 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)));
|
||||
}
|
||||
@ -356,6 +392,17 @@ public class EncryptFileFragment extends Fragment {
|
||||
switch (requestCode) {
|
||||
case RESULT_CODE_FILE: {
|
||||
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);
|
||||
@ -365,6 +412,7 @@ public class EncryptFileFragment extends Fragment {
|
||||
Log.e(Constants.TAG, "Nullpointer while retrieving path!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ public class EncryptMessageFragment extends Fragment {
|
||||
// fill values for this action
|
||||
Bundle data = new Bundle();
|
||||
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
|
||||
|
||||
String message = mMessage.getText().toString();
|
||||
|
||||
|
@ -21,9 +21,11 @@ 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;
|
||||
@ -34,6 +36,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
|
||||
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
|
||||
@ -49,6 +52,20 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
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();
|
||||
|
||||
args.putParcelable(ARG_DELETE_URI, deleteUri);
|
||||
|
||||
frag.setArguments(args);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates dialog
|
||||
*/
|
||||
@ -56,6 +73,7 @@ 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);
|
||||
|
||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
||||
@ -71,6 +89,12 @@ 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);
|
||||
|
||||
|
@ -23,10 +23,13 @@ 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;
|
||||
@ -50,6 +53,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_CHECKED = "checked";
|
||||
|
||||
@ -60,6 +64,9 @@ public class FileDialogFragment extends DialogFragment {
|
||||
private CheckBox mCheckBox;
|
||||
private TextView mMessageTextView;
|
||||
|
||||
private String mOutputFilename;
|
||||
private Uri mOutputUri;
|
||||
|
||||
private static final int REQUEST_CODE = 0x00007004;
|
||||
|
||||
/**
|
||||
@ -92,7 +99,7 @@ public class FileDialogFragment extends DialogFragment {
|
||||
|
||||
String title = getArguments().getString(ARG_TITLE);
|
||||
String message = getArguments().getString(ARG_MESSAGE);
|
||||
String defaultFile = getArguments().getString(ARG_DEFAULT_FILE);
|
||||
mOutputFilename = getArguments().getString(ARG_DEFAULT_FILE);
|
||||
String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) activity
|
||||
@ -106,15 +113,18 @@ public class FileDialogFragment extends DialogFragment {
|
||||
mMessageTextView.setText(message);
|
||||
|
||||
mFilename = (EditText) view.findViewById(R.id.input);
|
||||
mFilename.setText(defaultFile);
|
||||
mFilename.setText(mOutputFilename);
|
||||
mBrowse = (BootstrapButton) 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!
|
||||
FileHelper.openFile(FileDialogFragment.this, mFilename.getText().toString(), "*/*",
|
||||
REQUEST_CODE);
|
||||
if (Constants.KITKAT) {
|
||||
FileHelper.saveDocument(FileDialogFragment.this, mOutputUri, "*/*", REQUEST_CODE);
|
||||
} else {
|
||||
FileHelper.openFile(FileDialogFragment.this, mOutputFilename, "*/*", REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -136,13 +146,19 @@ public class FileDialogFragment extends DialogFragment {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dismiss();
|
||||
|
||||
boolean checked = false;
|
||||
if (mCheckBox.isEnabled()) {
|
||||
checked = mCheckBox.isChecked();
|
||||
String currentFilename = mFilename.getText().toString();
|
||||
if (mOutputFilename == null || !mOutputFilename.equals(currentFilename)) {
|
||||
mOutputUri = null;
|
||||
mOutputFilename = mFilename.getText().toString();
|
||||
}
|
||||
|
||||
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.putBoolean(MESSAGE_DATA_CHECKED, checked);
|
||||
|
||||
@ -178,6 +194,17 @@ public class FileDialogFragment extends DialogFragment {
|
||||
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();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
String path = data.getData().getPath();
|
||||
Log.d(Constants.TAG, "path=" + path);
|
||||
@ -188,6 +215,7 @@ public class FileDialogFragment extends DialogFragment {
|
||||
Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user